From adf040ddd00152bda99aa9bc2afef9075ac88b34 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 Dec 2018 13:50:25 -0600 Subject: ide: Use of_node_name_eq for node name comparisons Convert string compares of DT node names to use of_node_name_eq helper instead. This removes direct access to the node name pointer. Cc: "David S. Miller" Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: linux-ide@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring Signed-off-by: David S. Miller --- drivers/ide/pmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c index 203ed4adc04a..92f840365718 100644 --- a/drivers/ide/pmac.c +++ b/drivers/ide/pmac.c @@ -1046,7 +1046,7 @@ static int pmac_ide_setup_device(pmac_ide_hwif_t *pmif, struct ide_hw *hw) d.port_ops = &pmac_ide_ata4_port_ops; d.udma_mask = ATA_UDMA5; } else if (of_device_is_compatible(np, "keylargo-ata")) { - if (strcmp(np->name, "ata-4") == 0) { + if (of_node_name_eq(np, "ata-4")) { pmif->kind = controller_kl_ata4; d.port_ops = &pmac_ide_ata4_port_ops; d.udma_mask = ATA_UDMA4; -- cgit v1.2.3 From 53a6f022b4fe8645468adaffca901dbf8c3c547e Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Tue, 11 Dec 2018 17:54:53 -0700 Subject: staging: iio: adt7316: fix register and bit definitions Change two register addresses and one bit definition to match the datasheet. Note that there are many issues in this driver so I would not suggest backporting these fixes to stable trees. Signed-off-by: Jeremy Fertic Fixes: 35f6b6b86ede ("staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver") Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index dc93e85808e0..1fa4a4c2b4f3 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -59,8 +59,8 @@ #define ADT7316_CONFIG1 0x18 #define ADT7316_CONFIG2 0x19 #define ADT7316_CONFIG3 0x1A -#define ADT7316_LDAC_CONFIG 0x1B -#define ADT7316_DAC_CONFIG 0x1C +#define ADT7316_DAC_CONFIG 0x1B +#define ADT7316_LDAC_CONFIG 0x1C #define ADT7316_INT_MASK1 0x1D #define ADT7316_INT_MASK2 0x1E #define ADT7316_IN_TEMP_OFFSET 0x1F @@ -117,7 +117,7 @@ */ #define ADT7316_ADCLK_22_5 0x1 #define ADT7316_DA_HIGH_RESOLUTION 0x2 -#define ADT7316_DA_EN_VIA_DAC_LDCA 0x4 +#define ADT7316_DA_EN_VIA_DAC_LDCA 0x8 #define ADT7516_AIN_IN_VREF 0x10 #define ADT7316_EN_IN_TEMP_PROP_DACA 0x20 #define ADT7316_EN_EX_TEMP_PROP_DACB 0x40 -- cgit v1.2.3 From 85a1c11913312132d0800ca2c1c42a011f96ea92 Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Tue, 11 Dec 2018 17:54:54 -0700 Subject: staging: iio: adt7316: invert the logic of the check for an ldac pin ADT7316_DA_EN_VIA_DAC_LDCA is set when the dac and ldac registers are being used to update the dacs instead of the ldac pin. ADT7516_SEL_AIN3 is an adc input that shares the ldac pin. Only set these bits if an ldac pin is not being used. This could be backported to stable, but note there are various other bugs that probably make that a waste of time. Signed-off-by: Jeremy Fertic Fixes: 35f6b6b86ede ("staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver") Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 1fa4a4c2b4f3..e5e1f9d6357f 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -2130,7 +2130,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, return ret; } - if (chip->ldac_pin) { + if (!chip->ldac_pin) { chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA; if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) chip->config1 |= ADT7516_SEL_AIN3; -- cgit v1.2.3 From 5107d16e0aa4f56925c1627830c0e901782350df Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Tue, 11 Dec 2018 17:54:59 -0700 Subject: staging: iio: adt7316: use correct variable in DAC_internal_Vref read The dac internal vref settings are part of the ldac config register rather than the dac config register. Change the variable being used so the read returns the correct result. Whilst a fix, it is for a driver in heavy churn so do not backport to stable without taking considerable care and testing. Signed-off-by: Jeremy Fertic Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index e5e1f9d6357f..c1050dc678cf 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -1061,10 +1061,10 @@ static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev, if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) return sprintf(buf, "0x%x\n", - (chip->dac_config & ADT7516_DAC_IN_VREF_MASK) >> + (chip->ldac_config & ADT7516_DAC_IN_VREF_MASK) >> ADT7516_DAC_IN_VREF_OFFSET); return sprintf(buf, "%d\n", - !!(chip->dac_config & ADT7316_DAC_IN_VREF)); + !!(chip->ldac_config & ADT7316_DAC_IN_VREF)); } static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, -- cgit v1.2.3 From 10bfe7cc1739c22f0aa296b39e53f61e9e3f4d99 Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Tue, 11 Dec 2018 17:55:00 -0700 Subject: staging: iio: adt7316: allow adt751x to use internal vref for all dacs With adt7516/7/9, internal vref is available for dacs a and b, dacs c and d, or all dacs. The driver doesn't currently support internal vref for all dacs. Change the else if to an if so both bits are checked rather than just one or the other. Signed-off-by: Jeremy Fertic Fixes: 35f6b6b86ede ("staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver") Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index c1050dc678cf..ab6de60a94ae 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -1086,7 +1086,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, ldac_config = chip->ldac_config & (~ADT7516_DAC_IN_VREF_MASK); if (data & 0x1) ldac_config |= ADT7516_DAC_AB_IN_VREF; - else if (data & 0x2) + if (data & 0x2) ldac_config |= ADT7516_DAC_CD_IN_VREF; } else { ret = kstrtou8(buf, 16, &data); -- cgit v1.2.3 From 9f287a1c3fffbc10360d7490f5361fff0255a93d Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Tue, 11 Dec 2018 17:55:01 -0700 Subject: staging: iio: adt7316: remove dac vref buffer bypass from adt751x The option to allow the external vref to bypass the reference buffer is only available for adt7316/7/8. Remove the attributes for adt751x as well as the chip->id checks from the show and store functions. Signed-off-by: Jeremy Fertic Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index ab6de60a94ae..0ee925edad04 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -969,9 +969,6 @@ static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) - return -EPERM; - return sprintf(buf, "%d\n", !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_AB)); } @@ -986,9 +983,6 @@ static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev, u8 dac_config; int ret; - if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) - return -EPERM; - dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_AB); if (buf[0] == '1') dac_config |= ADT7316_VREF_BYPASS_DAC_AB; @@ -1014,9 +1008,6 @@ static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) - return -EPERM; - return sprintf(buf, "%d\n", !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_CD)); } @@ -1031,9 +1022,6 @@ static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev, u8 dac_config; int ret; - if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) - return -EPERM; - dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_CD); if (buf[0] == '1') dac_config |= ADT7316_VREF_BYPASS_DAC_CD; @@ -1710,8 +1698,6 @@ static struct attribute *adt7516_attributes[] = { &iio_dev_attr_DAC_update_mode.dev_attr.attr, &iio_dev_attr_all_DAC_update_modes.dev_attr.attr, &iio_dev_attr_update_DAC.dev_attr.attr, - &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr, - &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr, &iio_dev_attr_DAC_internal_Vref.dev_attr.attr, &iio_dev_attr_VDD.dev_attr.attr, &iio_dev_attr_in_temp.dev_attr.attr, -- cgit v1.2.3 From 32f228cb2ac7ce46cbc3dc0188ea94157039c69a Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Tue, 11 Dec 2018 17:55:02 -0700 Subject: staging: iio: adt7316: change interpretation of write to dac update mode Based on the output of adt7316_show_all_DAC_update_modes() and adt7316_show_DAC_update_mode(), adt7316_store_DAC_update_mode() should expect the user to enter an integer input from 0 to 3. The user input is currently expected to account for the actual bit positions in the register. For example, choosing option 3 would require a write of 0x30 (actually 48 since it expects base 10). To address this inconsistency, create a shift macro to be used in the valid input check as well as the calculation for the register write. Signed-off-by: Jeremy Fertic Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 0ee925edad04..773ce92482db 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -127,6 +127,7 @@ */ #define ADT7316_DA_2VREF_CH_MASK 0xF #define ADT7316_DA_EN_MODE_MASK 0x30 +#define ADT7316_DA_EN_MODE_SHIFT 4 #define ADT7316_DA_EN_MODE_SINGLE 0x00 #define ADT7316_DA_EN_MODE_AB_CD 0x10 #define ADT7316_DA_EN_MODE_ABCD 0x20 @@ -884,11 +885,11 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev, return -EPERM; ret = kstrtou8(buf, 10, &data); - if (ret || data > ADT7316_DA_EN_MODE_MASK) + if (ret || data > (ADT7316_DA_EN_MODE_MASK >> ADT7316_DA_EN_MODE_SHIFT)) return -EINVAL; dac_config = chip->dac_config & (~ADT7316_DA_EN_MODE_MASK); - dac_config |= data; + dac_config |= data << ADT7316_DA_EN_MODE_SHIFT; ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config); if (ret) -- cgit v1.2.3 From 618ab57f95bd15bfa153a6901a19a8c10e816156 Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Tue, 11 Dec 2018 17:55:03 -0700 Subject: staging: iio: adt7316: correct spelling of ADT7316_DA_EN_VIA_DAC_LDCA Change LDCA to LDAC. Signed-off-by: Jeremy Fertic Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 773ce92482db..23e20dbc873e 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -117,7 +117,7 @@ */ #define ADT7316_ADCLK_22_5 0x1 #define ADT7316_DA_HIGH_RESOLUTION 0x2 -#define ADT7316_DA_EN_VIA_DAC_LDCA 0x8 +#define ADT7316_DA_EN_VIA_DAC_LDAC 0x8 #define ADT7516_AIN_IN_VREF 0x10 #define ADT7316_EN_IN_TEMP_PROP_DACA 0x20 #define ADT7316_EN_EX_TEMP_PROP_DACB 0x40 @@ -852,7 +852,7 @@ static ssize_t adt7316_show_DAC_update_mode(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)) + if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC)) return sprintf(buf, "manual\n"); switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) { @@ -881,7 +881,7 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev, u8 data; int ret; - if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)) + if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC)) return -EPERM; ret = kstrtou8(buf, 10, &data); @@ -912,7 +912,7 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) + if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC) return sprintf(buf, "0 - auto at any MSB DAC writing\n" "1 - auto at MSB DAC AB and CD writing\n" "2 - auto at MSB DAC ABCD writing\n" @@ -934,7 +934,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev, u8 data; int ret; - if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) { + if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC) { if ((chip->dac_config & ADT7316_DA_EN_MODE_MASK) != ADT7316_DA_EN_MODE_LDAC) return -EPERM; @@ -2118,7 +2118,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, } if (!chip->ldac_pin) { - chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA; + chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDAC; if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) chip->config1 |= ADT7516_SEL_AIN3; } -- cgit v1.2.3 From 1533e45748783ca971639b1b661509314a13ff8c Mon Sep 17 00:00:00 2001 From: Hardik Singh Rathore Date: Wed, 12 Dec 2018 22:17:46 +0530 Subject: staging: iio: adt7316: drop unnecessary initialization of variables Initialization is unnecessary when the variable is written before it is read. There were some occasions in which the driver would initialize `ret' during declaration without need. Purely a cosmetic change with no functional impact. Signed-off-by: Hardik Singh Rathore Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316-i2c.c | 6 +++--- drivers/staging/iio/addac/adt7316-spi.c | 4 ++-- drivers/staging/iio/addac/adt7316.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c index 2d51bd425662..0f26bc38edc6 100644 --- a/drivers/staging/iio/addac/adt7316-i2c.c +++ b/drivers/staging/iio/addac/adt7316-i2c.c @@ -43,7 +43,7 @@ static int adt7316_i2c_read(void *client, u8 reg, u8 *data) static int adt7316_i2c_write(void *client, u8 reg, u8 data) { struct i2c_client *cl = client; - int ret = 0; + int ret; ret = i2c_smbus_write_byte_data(cl, reg, data); if (ret < 0) @@ -55,7 +55,7 @@ static int adt7316_i2c_write(void *client, u8 reg, u8 data) static int adt7316_i2c_multi_read(void *client, u8 reg, u8 count, u8 *data) { struct i2c_client *cl = client; - int i, ret = 0; + int i, ret; if (count > ADT7316_REG_MAX_ADDR) count = ADT7316_REG_MAX_ADDR; @@ -74,7 +74,7 @@ static int adt7316_i2c_multi_read(void *client, u8 reg, u8 count, u8 *data) static int adt7316_i2c_multi_write(void *client, u8 reg, u8 count, u8 *data) { struct i2c_client *cl = client; - int i, ret = 0; + int i, ret; if (count > ADT7316_REG_MAX_ADDR) count = ADT7316_REG_MAX_ADDR; diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c index e75827e326a6..8294b9c1e3c2 100644 --- a/drivers/staging/iio/addac/adt7316-spi.c +++ b/drivers/staging/iio/addac/adt7316-spi.c @@ -27,7 +27,7 @@ static int adt7316_spi_multi_read(void *client, u8 reg, u8 count, u8 *data) { struct spi_device *spi_dev = client; u8 cmd[2]; - int ret = 0; + int ret; if (count > ADT7316_REG_MAX_ADDR) count = ADT7316_REG_MAX_ADDR; @@ -56,7 +56,7 @@ static int adt7316_spi_multi_write(void *client, u8 reg, u8 count, u8 *data) { struct spi_device *spi_dev = client; u8 buf[ADT7316_REG_MAX_ADDR + 2]; - int i, ret = 0; + int i, ret; if (count > ADT7316_REG_MAX_ADDR) count = ADT7316_REG_MAX_ADDR; diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 23e20dbc873e..c3a472f76ad0 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -2092,7 +2092,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, struct iio_dev *indio_dev; unsigned short *adt7316_platform_data = dev->platform_data; int irq_type = IRQF_TRIGGER_LOW; - int ret = 0; + int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); if (!indio_dev) -- cgit v1.2.3 From 7f6b6d553df71431e61dfd2691a184fc7538dbfc Mon Sep 17 00:00:00 2001 From: Shreeya Patel Date: Fri, 14 Dec 2018 01:13:35 +0530 Subject: Staging: iio: adt7316: Add all irq related code in adt7316_irq_setup() ADT7316 driver no more uses platform data and hence use device tree data instead of platform data for assigning irq_type field and implement this in adt7316_irq_setup function. Switch case figures out the type of irq and if it's the default case then assign the default value to the irq_type i.e. irq_type = IRQF_TRIGGER_LOW Move devm_request_threaded_irq() and assignment of chip->config1 into the adt7316_setup_irq() to unclutter the code in probe function. Signed-off-by: Shreeya Patel Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 52 +++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index c3a472f76ad0..9db49aa186bb 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -1796,6 +1796,43 @@ static irqreturn_t adt7316_event_handler(int irq, void *private) return IRQ_HANDLED; } +static int adt7316_setup_irq(struct iio_dev *indio_dev) +{ + struct adt7316_chip_info *chip = iio_priv(indio_dev); + int irq_type, ret; + + irq_type = irqd_get_trigger_type(irq_get_irq_data(chip->bus.irq)); + + switch (irq_type) { + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + break; + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_FALLING: + break; + default: + dev_info(&indio_dev->dev, "mode %d unsupported, using IRQF_TRIGGER_LOW\n", + irq_type); + irq_type = IRQF_TRIGGER_LOW; + break; + } + + ret = devm_request_threaded_irq(&indio_dev->dev, chip->bus.irq, + NULL, adt7316_event_handler, + irq_type | IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) { + dev_err(&indio_dev->dev, "failed to request irq %d\n", + chip->bus.irq); + return ret; + } + + if (irq_type & IRQF_TRIGGER_HIGH) + chip->config1 |= ADT7316_INT_POLARITY; + + return 0; +} + /* * Show mask of enabled interrupts in Hex. */ @@ -2090,8 +2127,6 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, { struct adt7316_chip_info *chip; struct iio_dev *indio_dev; - unsigned short *adt7316_platform_data = dev->platform_data; - int irq_type = IRQF_TRIGGER_LOW; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); @@ -2135,20 +2170,9 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, indio_dev->modes = INDIO_DIRECT_MODE; if (chip->bus.irq > 0) { - if (adt7316_platform_data[0]) - irq_type = adt7316_platform_data[0]; - - ret = devm_request_threaded_irq(dev, chip->bus.irq, - NULL, - adt7316_event_handler, - irq_type | IRQF_ONESHOT, - indio_dev->name, - indio_dev); + ret = adt7316_setup_irq(indio_dev); if (ret) return ret; - - if (irq_type & IRQF_TRIGGER_HIGH) - chip->config1 |= ADT7316_INT_POLARITY; } ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1); -- cgit v1.2.3 From c9d07120ab9a704927191ae44729f4b8abba797f Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Sat, 8 Dec 2018 16:19:08 -0200 Subject: staging: iio: ad5933: change regulator binging for vref Set a single voltage regulator for all voltage references. Remove voltage reference value from default platafrom data struct. Signed-off-by: Marcelo Schmitt Signed-off-by: Gabriel Capella Co-developed-by: Gabriel Capella Signed-off-by: Jonathan Cameron --- drivers/staging/iio/impedance-analyzer/ad5933.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 9e52384f5370..730bc397a26b 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -91,7 +91,6 @@ struct ad5933_platform_data { unsigned long ext_clk_hz; - unsigned short vref_mv; }; struct ad5933_state { @@ -113,7 +112,6 @@ struct ad5933_state { }; static struct ad5933_platform_data ad5933_default_pdata = { - .vref_mv = 3300, }; #define AD5933_CHANNEL(_type, _extend_name, _info_mask_separate, _address, \ @@ -691,7 +689,7 @@ static void ad5933_work(struct work_struct *work) static int ad5933_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int ret, voltage_uv = 0; + int ret; struct ad5933_platform_data *pdata = dev_get_platdata(&client->dev); struct ad5933_state *st; struct iio_dev *indio_dev; @@ -718,12 +716,12 @@ static int ad5933_probe(struct i2c_client *client, dev_err(&client->dev, "Failed to enable specified VDD supply\n"); return ret; } - voltage_uv = regulator_get_voltage(st->reg); + ret = regulator_get_voltage(st->reg); + + if (ret < 0) + goto error_disable_reg; - if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else - st->vref_mv = pdata->vref_mv; + st->vref_mv = ret / 1000; if (pdata->ext_clk_hz) { st->mclk_hz = pdata->ext_clk_hz; -- cgit v1.2.3 From 0e0a22aebd64319d0fbe765974ba1e6332d98543 Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Sat, 8 Dec 2018 16:19:38 -0200 Subject: staging: iio: ad5933: use clock framework for clock reference Add the option to specify the external clock (MCLK) using the clock framework. Also remove the old platform data structure. Signed-off-by: Marcelo Schmitt Signed-off-by: Gabriel Capella Co-developed-by: Gabriel Capella Signed-off-by: Jonathan Cameron --- drivers/staging/iio/impedance-analyzer/ad5933.c | 43 +++++++++++++------------ 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 730bc397a26b..3134295f014f 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -82,20 +83,10 @@ #define AD5933_POLL_TIME_ms 10 #define AD5933_INIT_EXCITATION_TIME_ms 100 -/** - * struct ad5933_platform_data - platform specific data - * @ext_clk_hz: the external clock frequency in Hz, if not set - * the driver uses the internal clock (16.776 MHz) - * @vref_mv: the external reference voltage in millivolt - */ - -struct ad5933_platform_data { - unsigned long ext_clk_hz; -}; - struct ad5933_state { struct i2c_client *client; struct regulator *reg; + struct clk *mclk; struct delayed_work work; struct mutex lock; /* Protect sensor state */ unsigned long mclk_hz; @@ -111,9 +102,6 @@ struct ad5933_state { unsigned int poll_time_jiffies; }; -static struct ad5933_platform_data ad5933_default_pdata = { -}; - #define AD5933_CHANNEL(_type, _extend_name, _info_mask_separate, _address, \ _scan_index, _realbits) { \ .type = (_type), \ @@ -690,9 +678,9 @@ static int ad5933_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; - struct ad5933_platform_data *pdata = dev_get_platdata(&client->dev); struct ad5933_state *st; struct iio_dev *indio_dev; + unsigned long ext_clk_hz = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); if (!indio_dev) @@ -704,9 +692,6 @@ static int ad5933_probe(struct i2c_client *client, mutex_init(&st->lock); - if (!pdata) - pdata = &ad5933_default_pdata; - st->reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(st->reg)) return PTR_ERR(st->reg); @@ -723,8 +708,21 @@ static int ad5933_probe(struct i2c_client *client, st->vref_mv = ret / 1000; - if (pdata->ext_clk_hz) { - st->mclk_hz = pdata->ext_clk_hz; + st->mclk = devm_clk_get(&client->dev, "mclk"); + if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) { + ret = PTR_ERR(st->mclk); + goto error_disable_reg; + } + + if (!IS_ERR(st->mclk)) { + ret = clk_prepare_enable(st->mclk); + if (ret < 0) + goto error_disable_reg; + ext_clk_hz = clk_get_rate(st->mclk); + } + + if (ext_clk_hz) { + st->mclk_hz = ext_clk_hz; st->ctrl_lb = AD5933_CTRL_EXT_SYSCLK; } else { st->mclk_hz = AD5933_INT_OSC_FREQ_Hz; @@ -744,7 +742,7 @@ static int ad5933_probe(struct i2c_client *client, ret = ad5933_register_ring_funcs_and_init(indio_dev); if (ret) - goto error_disable_reg; + goto error_disable_mclk; ret = ad5933_setup(st); if (ret) @@ -758,6 +756,8 @@ static int ad5933_probe(struct i2c_client *client, error_unreg_ring: iio_kfifo_free(indio_dev->buffer); +error_disable_mclk: + clk_disable_unprepare(st->mclk); error_disable_reg: regulator_disable(st->reg); @@ -772,6 +772,7 @@ static int ad5933_remove(struct i2c_client *client) iio_device_unregister(indio_dev); iio_kfifo_free(indio_dev->buffer); regulator_disable(st->reg); + clk_disable_unprepare(st->mclk); return 0; } -- cgit v1.2.3 From 243c5c9d7b6250ce5e03cd88e48a40f961251b4e Mon Sep 17 00:00:00 2001 From: Slawomir Stepien Date: Wed, 12 Dec 2018 18:02:27 +0100 Subject: staging: iio: adc: ad7280a: split ad7280_channel_init() to more functions The ad7280_channel_init function has been split into more specific functions to increase the code readability. The setting of channel's scan_type.shift to 0, has been removed, since it is the default value. Signed-off-by: Slawomir Stepien Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7280a.c | 133 ++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 14f6a3ced060..8439a4e23228 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -97,6 +97,10 @@ #define AD7280A_NUM_CH (AD7280A_AUX_ADC_6 - \ AD7280A_CELL_VOLTAGE_1 + 1) +#define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) ((d * AD7280A_CELLS_PER_DEV) + c) +#define AD7280A_CALC_TEMP_CHAN_NUM(d, c) ((d * AD7280A_CELLS_PER_DEV) + \ + c - AD7280A_CELLS_PER_DEV) + #define AD7280A_DEVADDR_MASTER 0 #define AD7280A_DEVADDR_ALL 0x1F /* 5-bit device address is sent LSB first */ @@ -496,63 +500,98 @@ static const struct attribute_group ad7280_attrs_group = { .attrs = ad7280_attributes, }; +static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i) +{ + chan->type = IIO_VOLTAGE; + chan->differential = 1; + chan->channel = i; + chan->channel2 = chan->channel + 1; +} + +static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i) +{ + chan->type = IIO_TEMP; + chan->channel = i; +} + +static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr, + int cnt) +{ + chan->indexed = 1; + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->address = addr; + chan->scan_index = cnt; + chan->scan_type.sign = 'u'; + chan->scan_type.realbits = 12; + chan->scan_type.storagebits = 32; +} + +static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan, + int cnt, int dev) +{ + chan->type = IIO_VOLTAGE; + chan->differential = 1; + chan->channel = 0; + chan->channel2 = dev * AD7280A_CELLS_PER_DEV; + chan->address = AD7280A_ALL_CELLS; + chan->indexed = 1; + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->scan_index = cnt; + chan->scan_type.sign = 'u'; + chan->scan_type.realbits = 32; + chan->scan_type.storagebits = 32; +} + +static void ad7280_timestamp_channel_init(struct iio_chan_spec *chan, int cnt) +{ + chan->type = IIO_TIMESTAMP; + chan->channel = -1; + chan->scan_index = cnt; + chan->scan_type.sign = 's'; + chan->scan_type.realbits = 64; + chan->scan_type.storagebits = 64; +} + +static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt) +{ + int addr, ch, i; + struct iio_chan_spec *chan; + + for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_AUX_ADC_6; ch++) { + chan = &st->channels[*cnt]; + + if (ch < AD7280A_AUX_ADC_1) { + i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch); + ad7280_voltage_channel_init(chan, i); + } else { + i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch); + ad7280_temp_channel_init(chan, i); + } + + addr = ad7280a_devaddr(dev) << 8 | ch; + ad7280_common_fields_init(chan, addr, *cnt); + + (*cnt)++; + } +} + static int ad7280_channel_init(struct ad7280_state *st) { - int dev, ch, cnt; + int dev, cnt = 0; st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 2, sizeof(*st->channels), GFP_KERNEL); if (!st->channels) return -ENOMEM; - for (dev = 0, cnt = 0; dev <= st->slave_num; dev++) - for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_AUX_ADC_6; - ch++, cnt++) { - if (ch < AD7280A_AUX_ADC_1) { - st->channels[cnt].type = IIO_VOLTAGE; - st->channels[cnt].differential = 1; - st->channels[cnt].channel = (dev * 6) + ch; - st->channels[cnt].channel2 = - st->channels[cnt].channel + 1; - } else { - st->channels[cnt].type = IIO_TEMP; - st->channels[cnt].channel = (dev * 6) + ch - 6; - } - st->channels[cnt].indexed = 1; - st->channels[cnt].info_mask_separate = - BIT(IIO_CHAN_INFO_RAW); - st->channels[cnt].info_mask_shared_by_type = - BIT(IIO_CHAN_INFO_SCALE); - st->channels[cnt].address = - ad7280a_devaddr(dev) << 8 | ch; - st->channels[cnt].scan_index = cnt; - st->channels[cnt].scan_type.sign = 'u'; - st->channels[cnt].scan_type.realbits = 12; - st->channels[cnt].scan_type.storagebits = 32; - st->channels[cnt].scan_type.shift = 0; - } + for (dev = 0; dev <= st->slave_num; dev++) + ad7280_init_dev_channels(st, dev, &cnt); - st->channels[cnt].type = IIO_VOLTAGE; - st->channels[cnt].differential = 1; - st->channels[cnt].channel = 0; - st->channels[cnt].channel2 = dev * 6; - st->channels[cnt].address = AD7280A_ALL_CELLS; - st->channels[cnt].indexed = 1; - st->channels[cnt].info_mask_separate = BIT(IIO_CHAN_INFO_RAW); - st->channels[cnt].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); - st->channels[cnt].scan_index = cnt; - st->channels[cnt].scan_type.sign = 'u'; - st->channels[cnt].scan_type.realbits = 32; - st->channels[cnt].scan_type.storagebits = 32; - st->channels[cnt].scan_type.shift = 0; + ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev); cnt++; - st->channels[cnt].type = IIO_TIMESTAMP; - st->channels[cnt].channel = -1; - st->channels[cnt].scan_index = cnt; - st->channels[cnt].scan_type.sign = 's'; - st->channels[cnt].scan_type.realbits = 64; - st->channels[cnt].scan_type.storagebits = 64; - st->channels[cnt].scan_type.shift = 0; + ad7280_timestamp_channel_init(&st->channels[cnt], cnt); return cnt + 1; } -- cgit v1.2.3 From 4b6374577fe751f60ffc24c7b95ce803a22b2476 Mon Sep 17 00:00:00 2001 From: Slawomir Stepien Date: Wed, 12 Dec 2018 18:02:28 +0100 Subject: staging: iio: adc: ad7280a: split ad7280_attr_init() to more functions The ad7280_attr_init function has been split into more specific functions to increase the code readability. Signed-off-by: Slawomir Stepien Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7280a.c | 110 +++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 8439a4e23228..d9df12665176 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -596,11 +596,75 @@ static int ad7280_channel_init(struct ad7280_state *st) return cnt + 1; } -static int ad7280_attr_init(struct ad7280_state *st) +static int ad7280_balance_switch_attr_init(struct iio_dev_attr *attr, + struct device *dev, int addr, int i) +{ + attr->address = addr; + attr->dev_attr.attr.mode = 0644; + attr->dev_attr.show = ad7280_show_balance_sw; + attr->dev_attr.store = ad7280_store_balance_sw; + attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, + "in%d-in%d_balance_switch_en", + i, i + 1); + if (!attr->dev_attr.attr.name) + return -ENOMEM; + + return 0; +} + +static int ad7280_balance_timer_attr_init(struct iio_dev_attr *attr, + struct device *dev, int addr, int i) +{ + attr->address = addr; + attr->dev_attr.attr.mode = 0644; + attr->dev_attr.show = ad7280_show_balance_timer; + attr->dev_attr.store = ad7280_store_balance_timer; + attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, + "in%d-in%d_balance_timer", + i, i + 1); + if (!attr->dev_attr.attr.name) + return -ENOMEM; + + return 0; +} + +static int ad7280_init_dev_attrs(struct ad7280_state *st, int dev, int *cnt) { - int dev, ch, cnt; - unsigned int index; + int addr, ch, i, ret; struct iio_dev_attr *iio_attr; + struct device *sdev = &st->spi->dev; + + for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; ch++) { + iio_attr = &st->iio_attr[*cnt]; + addr = ad7280a_devaddr(dev) << 8 | ch; + i = dev * AD7280A_CELLS_PER_DEV + ch; + + ret = ad7280_balance_switch_attr_init(iio_attr, sdev, addr, i); + if (ret < 0) + return ret; + + ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr; + + (*cnt)++; + iio_attr = &st->iio_attr[*cnt]; + addr = ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER + ch); + + ret = ad7280_balance_timer_attr_init(iio_attr, sdev, addr, i); + if (ret < 0) + return ret; + + ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr; + (*cnt)++; + } + + ad7280_attributes[*cnt] = NULL; + + return 0; +} + +static int ad7280_attr_init(struct ad7280_state *st) +{ + int dev, cnt = 0, ret; st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) * (st->slave_num + 1) * AD7280A_CELLS_PER_DEV, @@ -608,41 +672,11 @@ static int ad7280_attr_init(struct ad7280_state *st) if (!st->iio_attr) return -ENOMEM; - for (dev = 0, cnt = 0; dev <= st->slave_num; dev++) - for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; - ch++, cnt++) { - iio_attr = &st->iio_attr[cnt]; - index = dev * AD7280A_CELLS_PER_DEV + ch; - iio_attr->address = ad7280a_devaddr(dev) << 8 | ch; - iio_attr->dev_attr.attr.mode = 0644; - iio_attr->dev_attr.show = ad7280_show_balance_sw; - iio_attr->dev_attr.store = ad7280_store_balance_sw; - iio_attr->dev_attr.attr.name = - devm_kasprintf(&st->spi->dev, GFP_KERNEL, - "in%d-in%d_balance_switch_en", - index, index + 1); - if (!iio_attr->dev_attr.attr.name) - return -ENOMEM; - - ad7280_attributes[cnt] = &iio_attr->dev_attr.attr; - cnt++; - iio_attr = &st->iio_attr[cnt]; - iio_attr->address = ad7280a_devaddr(dev) << 8 | - (AD7280A_CB1_TIMER + ch); - iio_attr->dev_attr.attr.mode = 0644; - iio_attr->dev_attr.show = ad7280_show_balance_timer; - iio_attr->dev_attr.store = ad7280_store_balance_timer; - iio_attr->dev_attr.attr.name = - devm_kasprintf(&st->spi->dev, GFP_KERNEL, - "in%d-in%d_balance_timer", - index, index + 1); - if (!iio_attr->dev_attr.attr.name) - return -ENOMEM; - - ad7280_attributes[cnt] = &iio_attr->dev_attr.attr; - } - - ad7280_attributes[cnt] = NULL; + for (dev = 0; dev <= st->slave_num; dev++) { + ret = ad7280_init_dev_attrs(st, dev, &cnt); + if (ret < 0) + return ret; + } return 0; } -- cgit v1.2.3 From f1b753a0f866a834f5681506ac29b6ca0ee902b2 Mon Sep 17 00:00:00 2001 From: Hardik Singh Rathore Date: Wed, 12 Dec 2018 23:27:07 +0530 Subject: staging: iio: ad7816: drop unnecessary initialization of variables Initialization is unnecessary when the variable is written before it is read. There were some occasions in which the driver would initialize `ret' during declaration without need. Signed-off-by: Hardik Singh Rathore Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7816.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 5209651a1b25..ee50e7296795 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -65,7 +65,7 @@ enum ad7816_type { static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data) { struct spi_device *spi_dev = chip->spi_dev; - int ret = 0; + int ret; __be16 buf; gpiod_set_value(chip->rdwr_pin, 1); @@ -106,7 +106,7 @@ static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data) static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data) { struct spi_device *spi_dev = chip->spi_dev; - int ret = 0; + int ret; gpiod_set_value(chip->rdwr_pin, 1); gpiod_set_value(chip->rdwr_pin, 0); @@ -354,8 +354,7 @@ static int ad7816_probe(struct spi_device *spi_dev) { struct ad7816_chip_info *chip; struct iio_dev *indio_dev; - int ret = 0; - int i; + int i, ret; indio_dev = devm_iio_device_alloc(&spi_dev->dev, sizeof(*chip)); if (!indio_dev) -- cgit v1.2.3 From 17abc9ec68b73ddeb262a507a62421016b9c54d5 Mon Sep 17 00:00:00 2001 From: Tomasz Duszynski Date: Fri, 14 Dec 2018 19:28:01 +0100 Subject: iio: add IIO_MASSCONCENTRATION channel type Measuring particulate matter in ug / m3 (micro-grams per cubic meter) is de facto standard. Existing air quality sensors usually follow this convention and are capable of returning measurements using this unit. IIO currently does not offer suitable channel type for this type of measurements hence this patch adds this. In addition, extra modifiers are introduced used for distinguishing between fine pm1, pm2p5 and coarse pm4, pm10 particle measurements, i.e IIO_MOD_PM1, IIO_MOD_PM25 and IIO_MOD_PM4, IIO_MOD_PM10. pmX consists of particles with aerodynamic diameter less or equal to X micrometers. Signed-off-by: Tomasz Duszynski Acked-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 4f5cd9f60870..4700fd5d8c90 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -87,6 +87,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_GRAVITY] = "gravity", [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", + [IIO_MASSCONCENTRATION] = "massconcentration", }; static const char * const iio_modifier_names[] = { @@ -127,6 +128,10 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_Q] = "q", [IIO_MOD_CO2] = "co2", [IIO_MOD_VOC] = "voc", + [IIO_MOD_PM1] = "pm1", + [IIO_MOD_PM2P5] = "pm2p5", + [IIO_MOD_PM4] = "pm4", + [IIO_MOD_PM10] = "pm10", }; /* relies on pairs of these shared then separate */ -- cgit v1.2.3 From 232e0f6ddeaee104d64675fe7d0cc142cf955f35 Mon Sep 17 00:00:00 2001 From: Tomasz Duszynski Date: Fri, 14 Dec 2018 19:28:02 +0100 Subject: iio: chemical: add support for Sensirion SPS30 sensor Add support for Sensirion SPS30 particulate matter sensor. Signed-off-by: Tomasz Duszynski Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/Kconfig | 11 ++ drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/sps30.c | 407 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 419 insertions(+) create mode 100644 drivers/iio/chemical/sps30.c (limited to 'drivers') diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index b8e005be4f87..57832b4360e9 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -61,6 +61,17 @@ config IAQCORE iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds) sensors +config SPS30 + tristate "SPS30 particulate matter sensor" + depends on I2C + select CRC8 + help + Say Y here to build support for the Sensirion SPS30 particulate + matter sensor. + + To compile this driver as a module, choose M here: the module will + be called sps30. + config VZ89X tristate "SGX Sensortech MiCS VZ89X VOC sensor" depends on I2C diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile index 2f4c4ba4d781..9f42f4252151 100644 --- a/drivers/iio/chemical/Makefile +++ b/drivers/iio/chemical/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_BME680_I2C) += bme680_i2c.o obj-$(CONFIG_BME680_SPI) += bme680_spi.o obj-$(CONFIG_CCS811) += ccs811.o obj-$(CONFIG_IAQCORE) += ams-iaq-core.o +obj-$(CONFIG_SPS30) += sps30.o obj-$(CONFIG_VZ89X) += vz89x.o diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c new file mode 100644 index 000000000000..fa3cd409b90b --- /dev/null +++ b/drivers/iio/chemical/sps30.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sensirion SPS30 particulate matter sensor driver + * + * Copyright (c) Tomasz Duszynski + * + * I2C slave address: 0x69 + * + * TODO: + * - support for turning on fan cleaning + * - support for reading/setting auto cleaning interval + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPS30_CRC8_POLYNOMIAL 0x31 +/* max number of bytes needed to store PM measurements or serial string */ +#define SPS30_MAX_READ_SIZE 48 +/* sensor measures reliably up to 3000 ug / m3 */ +#define SPS30_MAX_PM 3000 + +/* SPS30 commands */ +#define SPS30_START_MEAS 0x0010 +#define SPS30_STOP_MEAS 0x0104 +#define SPS30_RESET 0xd304 +#define SPS30_READ_DATA_READY_FLAG 0x0202 +#define SPS30_READ_DATA 0x0300 +#define SPS30_READ_SERIAL 0xd033 + +enum { + PM1, + PM2P5, + PM4, + PM10, +}; + +struct sps30_state { + struct i2c_client *client; + /* + * Guards against concurrent access to sensor registers. + * Must be held whenever sequence of commands is to be executed. + */ + struct mutex lock; +}; + +DECLARE_CRC8_TABLE(sps30_crc8_table); + +static int sps30_write_then_read(struct sps30_state *state, u8 *txbuf, + int txsize, u8 *rxbuf, int rxsize) +{ + int ret; + + /* + * Sensor does not support repeated start so instead of + * sending two i2c messages in a row we just send one by one. + */ + ret = i2c_master_send(state->client, txbuf, txsize); + if (ret != txsize) + return ret < 0 ? ret : -EIO; + + if (!rxbuf) + return 0; + + ret = i2c_master_recv(state->client, rxbuf, rxsize); + if (ret != rxsize) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size) +{ + /* + * Internally sensor stores measurements in a following manner: + * + * PM1: upper two bytes, crc8, lower two bytes, crc8 + * PM2P5: upper two bytes, crc8, lower two bytes, crc8 + * PM4: upper two bytes, crc8, lower two bytes, crc8 + * PM10: upper two bytes, crc8, lower two bytes, crc8 + * + * What follows next are number concentration measurements and + * typical particle size measurement which we omit. + */ + u8 buf[SPS30_MAX_READ_SIZE] = { cmd >> 8, cmd }; + int i, ret = 0; + + switch (cmd) { + case SPS30_START_MEAS: + buf[2] = 0x03; + buf[3] = 0x00; + buf[4] = crc8(sps30_crc8_table, &buf[2], 2, CRC8_INIT_VALUE); + ret = sps30_write_then_read(state, buf, 5, NULL, 0); + break; + case SPS30_STOP_MEAS: + case SPS30_RESET: + ret = sps30_write_then_read(state, buf, 2, NULL, 0); + break; + case SPS30_READ_DATA_READY_FLAG: + case SPS30_READ_DATA: + case SPS30_READ_SERIAL: + /* every two data bytes are checksummed */ + size += size / 2; + ret = sps30_write_then_read(state, buf, 2, buf, size); + break; + } + + if (ret) + return ret; + + /* validate received data and strip off crc bytes */ + for (i = 0; i < size; i += 3) { + u8 crc = crc8(sps30_crc8_table, &buf[i], 2, CRC8_INIT_VALUE); + + if (crc != buf[i + 2]) { + dev_err(&state->client->dev, + "data integrity check failed\n"); + return -EIO; + } + + *data++ = buf[i]; + *data++ = buf[i + 1]; + } + + return 0; +} + +static s32 sps30_float_to_int_clamped(const u8 *fp) +{ + int val = get_unaligned_be32(fp); + int mantissa = val & GENMASK(22, 0); + /* this is fine since passed float is always non-negative */ + int exp = val >> 23; + int fraction, shift; + + /* special case 0 */ + if (!exp && !mantissa) + return 0; + + exp -= 127; + if (exp < 0) { + /* return values ranging from 1 to 99 */ + return ((((1 << 23) + mantissa) * 100) >> 23) >> (-exp); + } + + /* return values ranging from 100 to 300000 */ + shift = 23 - exp; + val = (1 << exp) + (mantissa >> shift); + if (val >= SPS30_MAX_PM) + return SPS30_MAX_PM * 100; + + fraction = mantissa & GENMASK(shift - 1, 0); + + return val * 100 + ((fraction * 100) >> shift); +} + +static int sps30_do_meas(struct sps30_state *state, s32 *data, int size) +{ + int i, ret, tries = 5; + u8 tmp[16]; + + while (tries--) { + ret = sps30_do_cmd(state, SPS30_READ_DATA_READY_FLAG, tmp, 2); + if (ret) + return -EIO; + + /* new measurements ready to be read */ + if (tmp[1] == 1) + break; + + msleep_interruptible(300); + } + + if (!tries) + return -ETIMEDOUT; + + ret = sps30_do_cmd(state, SPS30_READ_DATA, tmp, sizeof(int) * size); + if (ret) + return ret; + + for (i = 0; i < size; i++) + data[i] = sps30_float_to_int_clamped(&tmp[4 * i]); + + return 0; +} + +static irqreturn_t sps30_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct sps30_state *state = iio_priv(indio_dev); + int ret; + s32 data[4 + 2]; /* PM1, PM2P5, PM4, PM10, timestamp */ + + mutex_lock(&state->lock); + ret = sps30_do_meas(state, data, 4); + mutex_unlock(&state->lock); + if (ret) + goto err; + + iio_push_to_buffers_with_timestamp(indio_dev, data, + iio_get_time_ns(indio_dev)); +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int sps30_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct sps30_state *state = iio_priv(indio_dev); + int data[4], ret = -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_MASSCONCENTRATION: + mutex_lock(&state->lock); + /* read up to the number of bytes actually needed */ + switch (chan->channel2) { + case IIO_MOD_PM1: + ret = sps30_do_meas(state, data, 1); + break; + case IIO_MOD_PM2P5: + ret = sps30_do_meas(state, data, 2); + break; + case IIO_MOD_PM4: + ret = sps30_do_meas(state, data, 3); + break; + case IIO_MOD_PM10: + ret = sps30_do_meas(state, data, 4); + break; + } + mutex_unlock(&state->lock); + if (ret) + return ret; + + *val = data[chan->address] / 100; + *val2 = (data[chan->address] % 100) * 10000; + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_MASSCONCENTRATION: + switch (chan->channel2) { + case IIO_MOD_PM1: + case IIO_MOD_PM2P5: + case IIO_MOD_PM4: + case IIO_MOD_PM10: + *val = 0; + *val2 = 10000; + + return IIO_VAL_INT_PLUS_MICRO; + } + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +static const struct iio_info sps30_info = { + .read_raw = sps30_read_raw, +}; + +#define SPS30_CHAN(_index, _mod) { \ + .type = IIO_MASSCONCENTRATION, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## _mod, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .address = _mod, \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 19, \ + .storagebits = 32, \ + .endianness = IIO_CPU, \ + }, \ +} + +static const struct iio_chan_spec sps30_channels[] = { + SPS30_CHAN(0, PM1), + SPS30_CHAN(1, PM2P5), + SPS30_CHAN(2, PM4), + SPS30_CHAN(3, PM10), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static void sps30_stop_meas(void *data) +{ + struct sps30_state *state = data; + + sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0); +} + +static const unsigned long sps30_scan_masks[] = { 0x0f, 0x00 }; + +static int sps30_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct sps30_state *state; + u8 buf[32]; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EOPNOTSUPP; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*state)); + if (!indio_dev) + return -ENOMEM; + + state = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + state->client = client; + indio_dev->dev.parent = &client->dev; + indio_dev->info = &sps30_info; + indio_dev->name = client->name; + indio_dev->channels = sps30_channels; + indio_dev->num_channels = ARRAY_SIZE(sps30_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->available_scan_masks = sps30_scan_masks; + + mutex_init(&state->lock); + crc8_populate_msb(sps30_crc8_table, SPS30_CRC8_POLYNOMIAL); + + ret = sps30_do_cmd(state, SPS30_RESET, NULL, 0); + if (ret) { + dev_err(&client->dev, "failed to reset device\n"); + return ret; + } + msleep(300); + /* + * Power-on-reset causes sensor to produce some glitch on i2c bus and + * some controllers end up in error state. Recover simply by placing + * some data on the bus, for example STOP_MEAS command, which + * is NOP in this case. + */ + sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0); + + ret = sps30_do_cmd(state, SPS30_READ_SERIAL, buf, sizeof(buf)); + if (ret) { + dev_err(&client->dev, "failed to read serial number\n"); + return ret; + } + /* returned serial number is already NUL terminated */ + dev_info(&client->dev, "serial number: %s\n", buf); + + ret = sps30_do_cmd(state, SPS30_START_MEAS, NULL, 0); + if (ret) { + dev_err(&client->dev, "failed to start measurement\n"); + return ret; + } + + ret = devm_add_action_or_reset(&client->dev, sps30_stop_meas, state); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, + sps30_trigger_handler, NULL); + if (ret) + return ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id sps30_id[] = { + { "sps30" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sps30_id); + +static const struct of_device_id sps30_of_match[] = { + { .compatible = "sensirion,sps30" }, + { } +}; +MODULE_DEVICE_TABLE(of, sps30_of_match); + +static struct i2c_driver sps30_driver = { + .driver = { + .name = "sps30", + .of_match_table = sps30_of_match, + }, + .id_table = sps30_id, + .probe_new = sps30_probe, +}; +module_i2c_driver(sps30_driver); + +MODULE_AUTHOR("Tomasz Duszynski "); +MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From ce514124161ac2ceb13d10b6c40cbf05c8f0cc91 Mon Sep 17 00:00:00 2001 From: Andreas Brauchli Date: Thu, 13 Dec 2018 15:43:23 +0100 Subject: iio: chemical: sgp30: Support Sensirion SGP30/SGPC3 sensors Support Sensirion SGP30 and SGPC3 multi-pixel I2C gas sensors Supported Features: * Indoor Air Quality (IAQ) concentrations for - tVOC (in_concentration_voc_input) - CO2eq (in_concentration_co2_input) - SGP30 only IAQ concentrations are periodically read out by a background thread to allow the sensor to maintain its internal baseline. * Gas concentration signals - Ethanol (in_concentration_ethanol_raw) - H2 (in_concentration_h2_raw) - SGP30 only https://www.sensirion.com/file/datasheet_sgp30 https://www.sensirion.com/file/datasheet_sgpc3 Signed-off-by: Andreas Brauchli Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/sgp30.c | 591 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 592 insertions(+) create mode 100644 drivers/iio/chemical/sgp30.c (limited to 'drivers') diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile index 9f42f4252151..65bf0f89c0e4 100644 --- a/drivers/iio/chemical/Makefile +++ b/drivers/iio/chemical/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_BME680_I2C) += bme680_i2c.o obj-$(CONFIG_BME680_SPI) += bme680_spi.o obj-$(CONFIG_CCS811) += ccs811.o obj-$(CONFIG_IAQCORE) += ams-iaq-core.o +obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o obj-$(CONFIG_SPS30) += sps30.o obj-$(CONFIG_VZ89X) += vz89x.o diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c new file mode 100644 index 000000000000..8cc8fe5e356d --- /dev/null +++ b/drivers/iio/chemical/sgp30.c @@ -0,0 +1,591 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * sgp30.c - Support for Sensirion SGP Gas Sensors + * + * Copyright (C) 2018 Andreas Brauchli + * + * I2C slave address: 0x58 + * + * Datasheets: + * https://www.sensirion.com/file/datasheet_sgp30 + * https://www.sensirion.com/file/datasheet_sgpc3 + * + * TODO: + * - baseline support + * - humidity compensation + * - power mode switching (SGPC3) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SGP_WORD_LEN 2 +#define SGP_CRC8_POLYNOMIAL 0x31 +#define SGP_CRC8_INIT 0xff +#define SGP_CRC8_LEN 1 +#define SGP_CMD(cmd_word) cpu_to_be16(cmd_word) +#define SGP_CMD_DURATION_US 12000 +#define SGP_MEASUREMENT_DURATION_US 50000 +#define SGP_CMD_LEN SGP_WORD_LEN +#define SGP_CMD_MAX_BUF_SIZE (SGP_CMD_LEN + 2 * SGP_WORD_LEN) +#define SGP_MEASUREMENT_LEN 2 +#define SGP30_MEASURE_INTERVAL_HZ 1 +#define SGPC3_MEASURE_INTERVAL_HZ 2 +#define SGP_VERS_PRODUCT(data) ((((data)->feature_set) & 0xf000) >> 12) +#define SGP_VERS_RESERVED(data) ((((data)->feature_set) & 0x0800) >> 11) +#define SGP_VERS_GEN(data) ((((data)->feature_set) & 0x0600) >> 9) +#define SGP_VERS_ENG_BIT(data) ((((data)->feature_set) & 0x0100) >> 8) +#define SGP_VERS_MAJOR(data) ((((data)->feature_set) & 0x00e0) >> 5) +#define SGP_VERS_MINOR(data) (((data)->feature_set) & 0x001f) + +DECLARE_CRC8_TABLE(sgp_crc8_table); + +enum sgp_product_id { + SGP30 = 0, + SGPC3, +}; + +enum sgp30_channel_idx { + SGP30_IAQ_TVOC_IDX = 0, + SGP30_IAQ_CO2EQ_IDX, + SGP30_SIG_ETOH_IDX, + SGP30_SIG_H2_IDX, +}; + +enum sgpc3_channel_idx { + SGPC3_IAQ_TVOC_IDX = 10, + SGPC3_SIG_ETOH_IDX, +}; + +enum sgp_cmd { + SGP_CMD_IAQ_INIT = SGP_CMD(0x2003), + SGP_CMD_IAQ_MEASURE = SGP_CMD(0x2008), + SGP_CMD_GET_FEATURE_SET = SGP_CMD(0x202f), + SGP_CMD_GET_SERIAL_ID = SGP_CMD(0x3682), + + SGP30_CMD_MEASURE_SIGNAL = SGP_CMD(0x2050), + + SGPC3_CMD_MEASURE_RAW = SGP_CMD(0x2046), +}; + +struct sgp_version { + u8 major; + u8 minor; +}; + +struct sgp_crc_word { + __be16 value; + u8 crc8; +} __attribute__((__packed__)); + +union sgp_reading { + u8 start; + struct sgp_crc_word raw_words[4]; +}; + +enum _iaq_buffer_state { + IAQ_BUFFER_EMPTY = 0, + IAQ_BUFFER_DEFAULT_VALS, + IAQ_BUFFER_VALID, +}; + +struct sgp_data { + struct i2c_client *client; + struct task_struct *iaq_thread; + struct mutex data_lock; + unsigned long iaq_init_start_jiffies; + unsigned long iaq_defval_skip_jiffies; + u16 product_id; + u16 feature_set; + unsigned long measure_interval_jiffies; + enum sgp_cmd iaq_init_cmd; + enum sgp_cmd measure_iaq_cmd; + enum sgp_cmd measure_gas_signals_cmd; + union sgp_reading buffer; + union sgp_reading iaq_buffer; + enum _iaq_buffer_state iaq_buffer_state; +}; + +struct sgp_device { + const struct iio_chan_spec *channels; + int num_channels; +}; + +static const struct sgp_version supported_versions_sgp30[] = { + { + .major = 1, + .minor = 0, + }, +}; + +static const struct sgp_version supported_versions_sgpc3[] = { + { + .major = 0, + .minor = 4, + }, +}; + +static const struct iio_chan_spec sgp30_channels[] = { + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_VOC, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .address = SGP30_IAQ_TVOC_IDX, + }, + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_CO2, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .address = SGP30_IAQ_CO2EQ_IDX, + }, + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_ETHANOL, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .address = SGP30_SIG_ETOH_IDX, + }, + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_H2, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .address = SGP30_SIG_H2_IDX, + }, +}; + +static const struct iio_chan_spec sgpc3_channels[] = { + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_VOC, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .address = SGPC3_IAQ_TVOC_IDX, + }, + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_ETHANOL, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .address = SGPC3_SIG_ETOH_IDX, + }, +}; + +static const struct sgp_device sgp_devices[] = { + [SGP30] = { + .channels = sgp30_channels, + .num_channels = ARRAY_SIZE(sgp30_channels), + }, + [SGPC3] = { + .channels = sgpc3_channels, + .num_channels = ARRAY_SIZE(sgpc3_channels), + }, +}; + +/** + * sgp_verify_buffer() - verify the checksums of the data buffer words + * + * @data: SGP data + * @buf: Raw data buffer + * @word_count: Num data words stored in the buffer, excluding CRC bytes + * + * Return: 0 on success, negative error otherwise. + */ +static int sgp_verify_buffer(const struct sgp_data *data, + union sgp_reading *buf, size_t word_count) +{ + size_t size = word_count * (SGP_WORD_LEN + SGP_CRC8_LEN); + int i; + u8 crc; + u8 *data_buf = &buf->start; + + for (i = 0; i < size; i += SGP_WORD_LEN + SGP_CRC8_LEN) { + crc = crc8(sgp_crc8_table, &data_buf[i], SGP_WORD_LEN, + SGP_CRC8_INIT); + if (crc != data_buf[i + SGP_WORD_LEN]) { + dev_err(&data->client->dev, "CRC error\n"); + return -EIO; + } + } + + return 0; +} + +/** + * sgp_read_cmd() - reads data from sensor after issuing a command + * The caller must hold data->data_lock for the duration of the call. + * @data: SGP data + * @cmd: SGP Command to issue + * @buf: Raw data buffer to use + * @word_count: Num words to read, excluding CRC bytes + * + * Return: 0 on success, negative error otherwise. + */ +static int sgp_read_cmd(struct sgp_data *data, enum sgp_cmd cmd, + union sgp_reading *buf, size_t word_count, + unsigned long duration_us) +{ + int ret; + struct i2c_client *client = data->client; + size_t size = word_count * (SGP_WORD_LEN + SGP_CRC8_LEN); + u8 *data_buf; + + ret = i2c_master_send(client, (const char *)&cmd, SGP_CMD_LEN); + if (ret != SGP_CMD_LEN) + return -EIO; + usleep_range(duration_us, duration_us + 1000); + + if (word_count == 0) + return 0; + + data_buf = &buf->start; + ret = i2c_master_recv(client, data_buf, size); + if (ret < 0) + return ret; + if (ret != size) + return -EIO; + + return sgp_verify_buffer(data, buf, word_count); +} + +/** + * sgp_measure_iaq() - measure and retrieve IAQ values from sensor + * The caller must hold data->data_lock for the duration of the call. + * @data: SGP data + * + * Return: 0 on success, -EBUSY on default values, negative error + * otherwise. + */ + +static int sgp_measure_iaq(struct sgp_data *data) +{ + int ret; + /* data contains default values */ + bool default_vals = !time_after(jiffies, data->iaq_init_start_jiffies + + data->iaq_defval_skip_jiffies); + + ret = sgp_read_cmd(data, data->measure_iaq_cmd, &data->iaq_buffer, + SGP_MEASUREMENT_LEN, SGP_MEASUREMENT_DURATION_US); + if (ret < 0) + return ret; + + data->iaq_buffer_state = IAQ_BUFFER_DEFAULT_VALS; + + if (default_vals) + return -EBUSY; + + data->iaq_buffer_state = IAQ_BUFFER_VALID; + + return 0; +} + +static void sgp_iaq_thread_sleep_until(const struct sgp_data *data, + unsigned long sleep_jiffies) +{ + const long IAQ_POLL = 50000; + + while (!time_after(jiffies, sleep_jiffies)) { + usleep_range(IAQ_POLL, IAQ_POLL + 10000); + if (kthread_should_stop() || data->iaq_init_start_jiffies == 0) + return; + } +} + +static int sgp_iaq_threadfn(void *p) +{ + struct sgp_data *data = (struct sgp_data *)p; + unsigned long next_update_jiffies; + int ret; + + while (!kthread_should_stop()) { + mutex_lock(&data->data_lock); + if (data->iaq_init_start_jiffies == 0) { + ret = sgp_read_cmd(data, data->iaq_init_cmd, NULL, 0, + SGP_CMD_DURATION_US); + if (ret < 0) + goto unlock_sleep_continue; + data->iaq_init_start_jiffies = jiffies; + } + + ret = sgp_measure_iaq(data); + if (ret && ret != -EBUSY) { + dev_warn(&data->client->dev, + "IAQ measurement error [%d]\n", ret); + } +unlock_sleep_continue: + next_update_jiffies = jiffies + data->measure_interval_jiffies; + mutex_unlock(&data->data_lock); + sgp_iaq_thread_sleep_until(data, next_update_jiffies); + } + + return 0; +} + +static int sgp_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct sgp_data *data = iio_priv(indio_dev); + struct sgp_crc_word *words; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + mutex_lock(&data->data_lock); + if (data->iaq_buffer_state != IAQ_BUFFER_VALID) { + mutex_unlock(&data->data_lock); + return -EBUSY; + } + words = data->iaq_buffer.raw_words; + switch (chan->address) { + case SGP30_IAQ_TVOC_IDX: + case SGPC3_IAQ_TVOC_IDX: + *val = 0; + *val2 = be16_to_cpu(words[1].value); + ret = IIO_VAL_INT_PLUS_NANO; + break; + case SGP30_IAQ_CO2EQ_IDX: + *val = 0; + *val2 = be16_to_cpu(words[0].value); + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&data->data_lock); + break; + case IIO_CHAN_INFO_RAW: + mutex_lock(&data->data_lock); + if (chan->address == SGPC3_SIG_ETOH_IDX) { + if (data->iaq_buffer_state == IAQ_BUFFER_EMPTY) + ret = -EBUSY; + else + ret = 0; + words = data->iaq_buffer.raw_words; + } else { + ret = sgp_read_cmd(data, data->measure_gas_signals_cmd, + &data->buffer, SGP_MEASUREMENT_LEN, + SGP_MEASUREMENT_DURATION_US); + words = data->buffer.raw_words; + } + if (ret) { + mutex_unlock(&data->data_lock); + return ret; + } + + switch (chan->address) { + case SGP30_SIG_ETOH_IDX: + *val = be16_to_cpu(words[1].value); + ret = IIO_VAL_INT; + break; + case SGPC3_SIG_ETOH_IDX: + case SGP30_SIG_H2_IDX: + *val = be16_to_cpu(words[0].value); + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&data->data_lock); + break; + default: + return -EINVAL; + } + + return ret; +} + +static int sgp_check_compat(struct sgp_data *data, + unsigned int product_id) +{ + const struct sgp_version *supported_versions; + u16 ix, num_fs; + u16 product, generation, major, minor; + + /* driver does not match product */ + generation = SGP_VERS_GEN(data); + if (generation != 0) { + dev_err(&data->client->dev, + "incompatible product generation %d != 0", generation); + return -ENODEV; + } + + product = SGP_VERS_PRODUCT(data); + if (product != product_id) { + dev_err(&data->client->dev, + "sensor reports a different product: 0x%04hx\n", + product); + return -ENODEV; + } + + if (SGP_VERS_RESERVED(data)) + dev_warn(&data->client->dev, "reserved bit is set\n"); + + /* engineering samples are not supported: no interface guarantees */ + if (SGP_VERS_ENG_BIT(data)) + return -ENODEV; + + switch (product) { + case SGP30: + supported_versions = supported_versions_sgp30; + num_fs = ARRAY_SIZE(supported_versions_sgp30); + break; + case SGPC3: + supported_versions = supported_versions_sgpc3; + num_fs = ARRAY_SIZE(supported_versions_sgpc3); + break; + default: + return -ENODEV; + } + + major = SGP_VERS_MAJOR(data); + minor = SGP_VERS_MINOR(data); + for (ix = 0; ix < num_fs; ix++) { + if (major == supported_versions[ix].major && + minor >= supported_versions[ix].minor) + return 0; + } + dev_err(&data->client->dev, "unsupported sgp version: %d.%d\n", + major, minor); + + return -ENODEV; +} + +static void sgp_init(struct sgp_data *data) +{ + data->iaq_init_cmd = SGP_CMD_IAQ_INIT; + data->iaq_init_start_jiffies = 0; + data->iaq_buffer_state = IAQ_BUFFER_EMPTY; + switch (SGP_VERS_PRODUCT(data)) { + case SGP30: + data->measure_interval_jiffies = SGP30_MEASURE_INTERVAL_HZ * HZ; + data->measure_iaq_cmd = SGP_CMD_IAQ_MEASURE; + data->measure_gas_signals_cmd = SGP30_CMD_MEASURE_SIGNAL; + data->product_id = SGP30; + data->iaq_defval_skip_jiffies = 15 * HZ; + break; + case SGPC3: + data->measure_interval_jiffies = SGPC3_MEASURE_INTERVAL_HZ * HZ; + data->measure_iaq_cmd = SGPC3_CMD_MEASURE_RAW; + data->measure_gas_signals_cmd = SGPC3_CMD_MEASURE_RAW; + data->product_id = SGPC3; + data->iaq_defval_skip_jiffies = + 43 * data->measure_interval_jiffies; + break; + }; +} + +static const struct iio_info sgp_info = { + .read_raw = sgp_read_raw, +}; + +static const struct of_device_id sgp_dt_ids[] = { + { .compatible = "sensirion,sgp30", .data = (void *)SGP30 }, + { .compatible = "sensirion,sgpc3", .data = (void *)SGPC3 }, + { } +}; + +static int sgp_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct sgp_data *data; + const struct of_device_id *of_id; + unsigned long product_id; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + of_id = of_match_device(sgp_dt_ids, &client->dev); + if (of_id) + product_id = (unsigned long)of_id->data; + else + product_id = id->driver_data; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + crc8_populate_msb(sgp_crc8_table, SGP_CRC8_POLYNOMIAL); + mutex_init(&data->data_lock); + + /* get feature set version and write it to client data */ + ret = sgp_read_cmd(data, SGP_CMD_GET_FEATURE_SET, &data->buffer, 1, + SGP_CMD_DURATION_US); + if (ret < 0) + return ret; + + data->feature_set = be16_to_cpu(data->buffer.raw_words[0].value); + + ret = sgp_check_compat(data, product_id); + if (ret) + return ret; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &sgp_info; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = sgp_devices[product_id].channels; + indio_dev->num_channels = sgp_devices[product_id].num_channels; + + sgp_init(data); + + ret = devm_iio_device_register(&client->dev, indio_dev); + if (ret) { + dev_err(&client->dev, "failed to register iio device\n"); + return ret; + } + + data->iaq_thread = kthread_run(sgp_iaq_threadfn, data, + "%s-iaq", data->client->name); + + return 0; +} + +static int sgp_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct sgp_data *data = iio_priv(indio_dev); + + if (data->iaq_thread) + kthread_stop(data->iaq_thread); + + return 0; +} + +static const struct i2c_device_id sgp_id[] = { + { "sgp30", SGP30 }, + { "sgpc3", SGPC3 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, sgp_id); +MODULE_DEVICE_TABLE(of, sgp_dt_ids); + +static struct i2c_driver sgp_driver = { + .driver = { + .name = "sgp30", + .of_match_table = of_match_ptr(sgp_dt_ids), + }, + .probe = sgp_probe, + .remove = sgp_remove, + .id_table = sgp_id, +}; +module_i2c_driver(sgp_driver); + +MODULE_AUTHOR("Andreas Brauchli "); +MODULE_AUTHOR("Pascal Sachs "); +MODULE_DESCRIPTION("Sensirion SGP gas sensors"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 557e585c3fdba1f6cddb4516a82da53b52fd9963 Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Thu, 13 Dec 2018 14:46:15 +0200 Subject: staging: iio: adc: ad7606: Use wait-for-completion handler This patch replaces the use of wait_event_interruptible() with wait_for_completion_timeout() when reading the result of a single conversion. In this way, if the interrupt never occurs, the program will not remain blocked. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 14 +++++++------- drivers/staging/iio/adc/ad7606.h | 6 ++---- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 7308fa8fbb4c..379a99ed22af 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -119,12 +119,13 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) struct ad7606_state *st = iio_priv(indio_dev); int ret; - st->done = false; gpiod_set_value(st->gpio_convst, 1); - - ret = wait_event_interruptible(st->wq_data_avail, st->done); - if (ret) + ret = wait_for_completion_timeout(&st->completion, + msecs_to_jiffies(1000)); + if (!ret) { + ret = -ETIMEDOUT; goto error_ret; + } ret = ad7606_read_samples(st); if (ret == 0) @@ -389,8 +390,7 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) if (iio_buffer_enabled(indio_dev)) { schedule_work(&st->poll_work); } else { - st->done = true; - wake_up_interruptible(&st->wq_data_avail); + complete(&st->completion); } return IRQ_HANDLED; @@ -474,7 +474,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; - init_waitqueue_head(&st->wq_data_avail); + init_completion(&st->completion); ret = ad7606_reset(st); if (ret) diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 86188054b60b..a46843f96e0c 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -29,11 +29,9 @@ struct ad7606_chip_info { * @reg regulator info for the the power supply of the device * @poll_work work struct for continuously reading data from the device * into an IIO triggered buffer - * @wq_data_avail wait queue struct for buffer mode * @bops bus operations (SPI or parallel) * @range voltage range selection, selects which scale to apply * @oversampling oversampling selection - * @done marks whether reading data is done * @base_address address from where to read data in parallel operation * @lock protect sensor state from concurrent accesses to GPIOs * @gpio_convst GPIO descriptor for conversion start signal (CONVST) @@ -44,6 +42,7 @@ struct ad7606_chip_info { * @gpio_frstdata GPIO descriptor for reading from device when data * is being read on the first channel * @gpio_os GPIO descriptors to control oversampling on the device + * @complete completion to indicate end of conversion * @data buffer for reading data from the device */ @@ -52,11 +51,9 @@ struct ad7606_state { const struct ad7606_chip_info *chip_info; struct regulator *reg; struct work_struct poll_work; - wait_queue_head_t wq_data_avail; const struct ad7606_bus_ops *bops; unsigned int range; unsigned int oversampling; - bool done; void __iomem *base_address; struct mutex lock; /* protect sensor state */ @@ -66,6 +63,7 @@ struct ad7606_state { struct gpio_desc *gpio_standby; struct gpio_desc *gpio_frstdata; struct gpio_descs *gpio_os; + struct completion completion; /* * DMA (thus cache coherency maintenance) requires the -- cgit v1.2.3 From c0683bfd3772337353e95decc2bf0421058088f7 Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Thu, 13 Dec 2018 14:46:16 +0200 Subject: staging: iio: adc: ad7606: Use devm functions in probe Switch to devm version of request_irq, iio_triggered_buffer_setup, iio_device_register. To avoid potential ordering issues in probe, devm_add_action_or_reset() is used for the regulator_disable(). This simplifies the code and decreases the chance of bugs. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 59 +++++++++++++----------------------- drivers/staging/iio/adc/ad7606.h | 1 - drivers/staging/iio/adc/ad7606_par.c | 6 ---- drivers/staging/iio/adc/ad7606_spi.c | 6 ---- 4 files changed, 21 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 379a99ed22af..36ca75a9907b 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -418,6 +418,13 @@ static const struct iio_info ad7606_info_range = { .attrs = &ad7606_attribute_group_range, }; +static void ad7606_regulator_disable(void *data) +{ + struct ad7606_state *st = data; + + regulator_disable(st->reg); +} + int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, const char *name, unsigned int id, const struct ad7606_bus_ops *bops) @@ -431,6 +438,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, return -ENOMEM; st = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); st->dev = dev; mutex_init(&st->lock); @@ -451,11 +459,15 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, return ret; } + ret = devm_add_action_or_reset(dev, ad7606_regulator_disable, st); + if (ret) + return ret; + st->chip_info = &ad7606_chip_info_tbl[id]; ret = ad7606_request_gpios(st); if (ret) - goto error_disable_reg; + return ret; indio_dev->dev.parent = dev; if (st->gpio_os) { @@ -480,50 +492,21 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); - ret = request_irq(irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, name, - indio_dev); - if (ret) - goto error_disable_reg; - - ret = iio_triggered_buffer_setup(indio_dev, &ad7606_trigger_handler, - NULL, NULL); + ret = devm_request_irq(dev, irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, + name, indio_dev); if (ret) - goto error_free_irq; + return ret; - ret = iio_device_register(indio_dev); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &ad7606_trigger_handler, + NULL, NULL); if (ret) - goto error_unregister_ring; - - dev_set_drvdata(dev, indio_dev); - - return 0; -error_unregister_ring: - iio_triggered_buffer_cleanup(indio_dev); - -error_free_irq: - free_irq(irq, indio_dev); + return ret; -error_disable_reg: - regulator_disable(st->reg); - return ret; + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_GPL(ad7606_probe); -int ad7606_remove(struct device *dev, int irq) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - free_irq(irq, indio_dev); - regulator_disable(st->reg); - - return 0; -} -EXPORT_SYMBOL_GPL(ad7606_remove); - #ifdef CONFIG_PM_SLEEP static int ad7606_suspend(struct device *dev) diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index a46843f96e0c..510a93db362f 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -85,7 +85,6 @@ struct ad7606_bus_ops { int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, const char *name, unsigned int id, const struct ad7606_bus_ops *bops); -int ad7606_remove(struct device *dev, int irq); enum ad7606_supported_device_ids { ID_AD7605_4, diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index 8bd86e727b02..c04ce8ac97ff 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -72,11 +72,6 @@ static int ad7606_par_probe(struct platform_device *pdev) &ad7606_par8_bops); } -static int ad7606_par_remove(struct platform_device *pdev) -{ - return ad7606_remove(&pdev->dev, platform_get_irq(pdev, 0)); -} - static const struct platform_device_id ad7606_driver_ids[] = { { .name = "ad7605-4", @@ -98,7 +93,6 @@ MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); static struct platform_driver ad7606_driver = { .probe = ad7606_par_probe, - .remove = ad7606_par_remove, .id_table = ad7606_driver_ids, .driver = { .name = "ad7606", diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index b76ca5a8c059..f38594f38a31 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -49,11 +49,6 @@ static int ad7606_spi_probe(struct spi_device *spi) &ad7606_spi_bops); } -static int ad7606_spi_remove(struct spi_device *spi) -{ - return ad7606_remove(&spi->dev, spi->irq); -} - static const struct spi_device_id ad7606_id[] = { {"ad7605-4", ID_AD7605_4}, {"ad7606-8", ID_AD7606_8}, @@ -69,7 +64,6 @@ static struct spi_driver ad7606_driver = { .pm = AD7606_PM_OPS, }, .probe = ad7606_spi_probe, - .remove = ad7606_spi_remove, .id_table = ad7606_id, }; module_spi_driver(ad7606_driver); -- cgit v1.2.3 From 41f71e5e7dafb4608834d6e3be49b5568639c0c1 Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Thu, 13 Dec 2018 14:46:18 +0200 Subject: staging: iio: adc: ad7606: Use find_closest() macro When looking for the available scale or oversampling ratio, it is better to use the find_closest() macro. This simplifies the code and also does not require an exact value to be entered from the user space. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 58 +++++++++++++++------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 36ca75a9907b..d032590739e8 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -30,8 +31,12 @@ * Scales are computed as 5000/32768 and 10000/32768 respectively, * so that when applied to the raw values they provide mV values */ -static const unsigned int scale_avail[2][2] = { - {0, 152588}, {0, 305176} +static const unsigned int scale_avail[2] = { + 152588, 305176 +}; + +static const unsigned int ad7606_oversampling_avail[7] = { + 1, 2, 4, 8, 16, 32, 64, }; static int ad7606_reset(struct ad7606_state *st) @@ -160,8 +165,8 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, *val = (short)ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = scale_avail[st->range][0]; - *val2 = scale_avail[st->range][1]; + *val = 0; + *val2 = scale_avail[st->range]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling; @@ -177,8 +182,8 @@ static ssize_t in_voltage_scale_available_show(struct device *dev, int i, len = 0; for (i = 0; i < ARRAY_SIZE(scale_avail); i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ", - scale_avail[i][0], scale_avail[i][1]); + len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", + scale_avail[i]); buf[len - 1] = '\n'; @@ -187,18 +192,6 @@ static ssize_t in_voltage_scale_available_show(struct device *dev, static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); -static int ad7606_oversampling_get_index(unsigned int val) -{ - unsigned char supported[] = {1, 2, 4, 8, 16, 32, 64}; - int i; - - for (i = 0; i < ARRAY_SIZE(supported); i++) - if (val == supported[i]) - return i; - - return -EINVAL; -} - static int ad7606_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -207,36 +200,29 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, { struct ad7606_state *st = iio_priv(indio_dev); DECLARE_BITMAP(values, 3); - int ret, i; + int i; switch (mask) { case IIO_CHAN_INFO_SCALE: - ret = -EINVAL; mutex_lock(&st->lock); - for (i = 0; i < ARRAY_SIZE(scale_avail); i++) - if (val2 == scale_avail[i][1]) { - gpiod_set_value(st->gpio_range, i); - st->range = i; - - ret = 0; - break; - } + i = find_closest(val2, scale_avail, ARRAY_SIZE(scale_avail)); + gpiod_set_value(st->gpio_range, i); + st->range = i; mutex_unlock(&st->lock); - return ret; + return 0; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: if (val2) return -EINVAL; - ret = ad7606_oversampling_get_index(val); - if (ret < 0) - return ret; + i = find_closest(val, ad7606_oversampling_avail, + ARRAY_SIZE(ad7606_oversampling_avail)); - values[0] = ret; + values[0] = i; mutex_lock(&st->lock); - gpiod_set_array_value(3, st->gpio_os->desc, st->gpio_os->info, - values); - st->oversampling = val; + gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, + st->gpio_os->info, values); + st->oversampling = ad7606_oversampling_avail[i]; mutex_unlock(&st->lock); return 0; -- cgit v1.2.3 From 6620585a0c9ee75332346ef2dcb1c4a7573db57b Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Thu, 13 Dec 2018 14:46:19 +0200 Subject: staging: iio: adc: ad7606: Use vendor prefix for DT properties The 'adi' vendor prefix needs to be added to conversion-start, range, first-data and oversampling-ratio properties. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index d032590739e8..e1d85b7a0e4c 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -334,7 +334,7 @@ static int ad7606_request_gpios(struct ad7606_state *st) { struct device *dev = st->dev; - st->gpio_convst = devm_gpiod_get(dev, "conversion-start", + st->gpio_convst = devm_gpiod_get(dev, "adi,conversion-start", GPIOD_OUT_LOW); if (IS_ERR(st->gpio_convst)) return PTR_ERR(st->gpio_convst); @@ -343,7 +343,8 @@ static int ad7606_request_gpios(struct ad7606_state *st) if (IS_ERR(st->gpio_reset)) return PTR_ERR(st->gpio_reset); - st->gpio_range = devm_gpiod_get_optional(dev, "range", GPIOD_OUT_LOW); + st->gpio_range = devm_gpiod_get_optional(dev, "adi,range", + GPIOD_OUT_LOW); if (IS_ERR(st->gpio_range)) return PTR_ERR(st->gpio_range); @@ -352,7 +353,7 @@ static int ad7606_request_gpios(struct ad7606_state *st) if (IS_ERR(st->gpio_standby)) return PTR_ERR(st->gpio_standby); - st->gpio_frstdata = devm_gpiod_get_optional(dev, "first-data", + st->gpio_frstdata = devm_gpiod_get_optional(dev, "adi,first-data", GPIOD_IN); if (IS_ERR(st->gpio_frstdata)) return PTR_ERR(st->gpio_frstdata); @@ -360,7 +361,8 @@ static int ad7606_request_gpios(struct ad7606_state *st) if (!st->chip_info->has_oversampling) return 0; - st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio", + st->gpio_os = devm_gpiod_get_array_optional(dev, + "adi,oversampling-ratio", GPIOD_OUT_LOW); return PTR_ERR_OR_ZERO(st->gpio_os); } -- cgit v1.2.3 From 43f9b204edf033b6fb87f761c70a8f55462983ae Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Thu, 13 Dec 2018 14:46:20 +0200 Subject: staging: iio: adc: ad7606: Add OF device ID table The driver does not have a struct of_device_id table, but supported devices are registered via Device Trees. This patch adds and OF device ID table. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606_par.c | 10 ++++++++++ drivers/staging/iio/adc/ad7606_spi.c | 10 ++++++++++ 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index c04ce8ac97ff..da26742e8b46 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -91,12 +91,22 @@ static const struct platform_device_id ad7606_driver_ids[] = { MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); +static const struct of_device_id ad7606_of_match[] = { + { .compatible = "adi,ad7605-4" }, + { .compatible = "adi,ad7606-4" }, + { .compatible = "adi,ad7606-6" }, + { .compatible = "adi,ad7606-8" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ad7606_of_match); + static struct platform_driver ad7606_driver = { .probe = ad7606_par_probe, .id_table = ad7606_driver_ids, .driver = { .name = "ad7606", .pm = AD7606_PM_OPS, + .of_match_table = ad7606_of_match, }, }; diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index f38594f38a31..e533917db094 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -58,9 +58,19 @@ static const struct spi_device_id ad7606_id[] = { }; MODULE_DEVICE_TABLE(spi, ad7606_id); +static const struct of_device_id ad7606_of_match[] = { + { .compatible = "adi,ad7605-4" }, + { .compatible = "adi,ad7606-4" }, + { .compatible = "adi,ad7606-6" }, + { .compatible = "adi,ad7606-8" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ad7606_of_match); + static struct spi_driver ad7606_driver = { .driver = { .name = "ad7606", + .of_match_table = ad7606_of_match, .pm = AD7606_PM_OPS, }, .probe = ad7606_spi_probe, -- cgit v1.2.3 From 6a4b8937a3d6238b5aa9b9c8083f7238903bfb86 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 15 Dec 2018 06:31:24 +0000 Subject: iio: imu: st_lsm6dsx: remove set but not used variable '' Fixes gcc '-Wunused-but-set-variable' warning: drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c: In function 'st_lsm6dsx_shub_read_reg': drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c:108:41: warning: variable 'hub_settings' set but not used [-Wunused-but-set-variable] It never used since introduction in commit c91c1c844ebd ("iio: imu: st_lsm6dsx: add i2c embedded controller support") Signed-off-by: YueHaibing Acked-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index 8e47dccdd40f..66fbcd94642d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -105,12 +105,10 @@ static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw) static int st_lsm6dsx_shub_read_reg(struct st_lsm6dsx_hw *hw, u8 addr, u8 *data, int len) { - const struct st_lsm6dsx_shub_settings *hub_settings; int err; mutex_lock(&hw->page_lock); - hub_settings = &hw->settings->shub_settings; err = st_lsm6dsx_set_page(hw, true); if (err < 0) goto out; -- cgit v1.2.3 From 5eb8ba90958de1285120dae5d3a5d2b1a360b3b4 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:10:01 -0500 Subject: clk: highbank: fix refcount leak in hb_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 26cae166cff9 ("ARM: highbank: remove custom .init_time hook") Signed-off-by: Stephen Boyd --- drivers/clk/clk-highbank.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c index 727ed8e1bb72..8e4581004695 100644 --- a/drivers/clk/clk-highbank.c +++ b/drivers/clk/clk-highbank.c @@ -293,6 +293,7 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk /* Map system registers */ srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); hb_clk->reg = of_iomap(srnp, 0); + of_node_put(srnp); BUG_ON(!hb_clk->reg); hb_clk->reg += reg; -- cgit v1.2.3 From 70af6c5b5270e8101f318c4b69cc98a726edfab9 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:14:42 -0500 Subject: clk: qoriq: fix refcount leak in clockgen_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") Signed-off-by: Stephen Boyd --- drivers/clk/clk-qoriq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 4c30b6e799ed..97a0029a1cca 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -1389,6 +1389,7 @@ static void __init clockgen_init(struct device_node *np) pr_err("%s: Couldn't map %pOF regs\n", __func__, guts); } + of_node_put(guts); } } -- cgit v1.2.3 From 2274d8001fbb5e1942fbcab5ad2eb15553b09ed2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:21:31 -0500 Subject: clk: ti: fix refcount leak in ti_dt_clocks_register() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 5b385a45e001 ("clk: ti: add support for clkctrl aliases") Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index d0cd58534781..5174f9a91679 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -191,9 +191,13 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) clkdev_add(&c->lk); } else { if (num_args && !has_clkctrl_data) { - if (of_find_compatible_node(NULL, NULL, - "ti,clkctrl")) { + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, + "ti,clkctrl"); + if (np) { has_clkctrl_data = true; + of_node_put(np); } else { clkctrl_nodes_missing = true; -- cgit v1.2.3 From 7f9705beeb3759e69165e7aff588f6488ff6c1ac Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:29:02 -0500 Subject: clk: socfpga: fix refcount leak The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 5343325ff3dd ("clk: socfpga: add a clock driver for the Arria 10 platform") Fixes: a30d27ed739b ("clk: socfpga: fix clock driver for 3.15") Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-pll-a10.c | 1 + drivers/clk/socfpga/clk-pll.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index 35fabe1a32c3..269467e8e07e 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -95,6 +95,7 @@ static struct clk * __init __socfpga_pll_init(struct device_node *node, clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_a10_base_addr = of_iomap(clkmgr_np, 0); + of_node_put(clkmgr_np); BUG_ON(!clk_mgr_a10_base_addr); pll_clk->hw.reg = clk_mgr_a10_base_addr + reg; diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index c7f463172e4b..b4b44e9b5901 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -100,6 +100,7 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_base_addr = of_iomap(clkmgr_np, 0); + of_node_put(clkmgr_np); BUG_ON(!clk_mgr_base_addr); pll_clk->hw.reg = clk_mgr_base_addr + reg; -- cgit v1.2.3 From cee82eb9532090cd1dc953e845d71f9b1445c84e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:32:15 -0500 Subject: clk: samsung: exynos4: fix refcount leak in exynos4_get_xom() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: e062b571777f ("clk: exynos4: register clocks using common clock framework") Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-exynos4.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 59d4d46667ce..54066e6508d3 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1028,6 +1028,7 @@ static unsigned long __init exynos4_get_xom(void) xom = readl(chipid_base + 8); iounmap(chipid_base); + of_node_put(np); } return xom; -- cgit v1.2.3 From c9ec1d8fef31b5fc9e90e99f9bd685db5caa7c5e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:53:00 -0500 Subject: clk: imx6q: fix refcount leak in imx6q_clocks_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 2acd1b6f889c ("ARM: i.MX6: implement clocks using common clock framework") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6q.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index bbe0c60f4d09..53617e0632a9 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -424,6 +424,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); anatop_base = base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); /* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { -- cgit v1.2.3 From 1731e14fb30212dd8c1e9f8fc1af061e56498c55 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:55:10 -0500 Subject: clk: imx6sx: fix refcount leak in imx6sx_clocks_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: d55135689019 ("ARM: imx: add clock driver for imx6sx") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6sx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index 18527a335ace..91558b09bf9e 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -151,6 +151,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); -- cgit v1.2.3 From 5f8c183a996b76bb09748073c856e4246fd4ce95 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:57:16 -0500 Subject: clk: imx7d: fix refcount leak in imx7d_clocks_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 8f6d8094b215 ("ARM: imx: add imx7d clk tree support") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx7d.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index adb08f64c691..12e2e85bbe1c 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -404,6 +404,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); clks[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel)); clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel)); -- cgit v1.2.3 From 567177024e0313e4f0dcba7ba10c0732e50e655d Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:59:36 -0500 Subject: clk: vf610: fix refcount leak in vf610_clocks_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 1f2c5fd5f048 ("ARM: imx: add VF610 clock support") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-vf610.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 6dae54325a91..a334667c450a 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -203,6 +203,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop"); anatop_base = of_iomap(np, 0); BUG_ON(!anatop_base); + of_node_put(np); np = ccm_node; ccm_base = of_iomap(np, 0); -- cgit v1.2.3 From a3c24050bdf70c958a8d98c2823b66ea761e6a31 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:36:58 -0500 Subject: clk: armada-370: fix refcount leak in a370_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 07ad6836fa21 ("clk: mvebu: armada-370: maintain clock init order") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-370.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c index 7dedfaa6e152..5c6bbee396b3 100644 --- a/drivers/clk/mvebu/armada-370.c +++ b/drivers/clk/mvebu/armada-370.c @@ -175,8 +175,10 @@ static void __init a370_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &a370_coreclks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, a370_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init); -- cgit v1.2.3 From e7beeab9c61591cd0e690d8733d534c3f4278ff8 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:40:19 -0500 Subject: clk: kirkwood: fix refcount leak in kirkwood_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 58d516ae95cb ("clk: mvebu: kirkwood: maintain clock init order") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/kirkwood.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index 6f784167bda4..35af3aa18f1c 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c @@ -331,6 +331,8 @@ static void __init kirkwood_clk_init(struct device_node *np) if (cgnp) { mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc); + + of_node_put(cgnp); } } CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", -- cgit v1.2.3 From db20a90a4b6745dad62753f8bd2f66afdd5abc84 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:42:26 -0500 Subject: clk: armada-xp: fix refcount leak in axp_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 0a11a6ae9437 ("clk: mvebu: armada-xp: maintain clock init order") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-xp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c index e8f03293ec83..fa1568279c23 100644 --- a/drivers/clk/mvebu/armada-xp.c +++ b/drivers/clk/mvebu/armada-xp.c @@ -226,7 +226,9 @@ static void __init axp_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &axp_coreclks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, axp_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init); -- cgit v1.2.3 From 9b4eedf627045ae5ddcff60a484200cdd554c413 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:48:05 -0500 Subject: clk: mv98dx3236: fix refcount leak in mv98dx3236_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 337072604224 ("clk: mvebu: Expand mv98dx3236-core-clock support") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/mv98dx3236.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/mvebu/mv98dx3236.c b/drivers/clk/mvebu/mv98dx3236.c index 0a74cf7a7725..1c8ab4f834ba 100644 --- a/drivers/clk/mvebu/mv98dx3236.c +++ b/drivers/clk/mvebu/mv98dx3236.c @@ -172,7 +172,9 @@ static void __init mv98dx3236_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &mv98dx3236_core_clocks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init); -- cgit v1.2.3 From 8d726c5128298386b907963033be93407b0c4275 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:50:13 -0500 Subject: clk: dove: fix refcount leak in dove_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 8f7fc5450b64 ("clk: mvebu: dove: maintain clock init order") Fixes: 63b8d92c793f ("clk: add Dove PLL divider support for GPU, VMeta and AXI clocks") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/dove.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c index e0dd99f36bf4..0bd09d33f9cf 100644 --- a/drivers/clk/mvebu/dove.c +++ b/drivers/clk/mvebu/dove.c @@ -188,10 +188,14 @@ static void __init dove_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &dove_coreclks); - if (ddnp) + if (ddnp) { dove_divider_clk_init(ddnp); + of_node_put(ddnp); + } - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, dove_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init); -- cgit v1.2.3 From 4cac31e2be6e569bd55f936e662d2d146325b74c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 29 Dec 2018 19:40:47 +0800 Subject: regulator: lochnagar: Set up correct .data field for "cirrus,lochnagar2-mic2vdd" Fix trival copy-n-paste mistake. Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/regulator/lochnagar-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/lochnagar-regulator.c b/drivers/regulator/lochnagar-regulator.c index 5a89e6d4b9a6..818d20410518 100644 --- a/drivers/regulator/lochnagar-regulator.c +++ b/drivers/regulator/lochnagar-regulator.c @@ -226,7 +226,7 @@ static const struct of_device_id lochnagar_of_match[] = { }, { .compatible = "cirrus,lochnagar2-mic2vdd", - .data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD], + .data = &lochnagar_regulators[LOCHNAGAR_MIC2VDD], }, { .compatible = "cirrus,lochnagar2-vddcore", -- cgit v1.2.3 From 082531444e454bac6f743ec064203bf8812bc9ac Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 1 Jan 2019 22:10:53 +0800 Subject: spi: npcm-pspi: Fix wrong priv pointer In npcm_pspi_probe(), current code set platform_set_drvdata(pdev, master); so in npcm_pspi_remove() platform_get_drvdata(pdev) will return pointer to master rather than priv. Fix it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-pspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index e1dca79b9090..734a2b956959 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -465,7 +465,8 @@ out_master_put: static int npcm_pspi_remove(struct platform_device *pdev) { - struct npcm_pspi *priv = platform_get_drvdata(pdev); + struct spi_master *master = platform_get_drvdata(pdev); + struct npcm_pspi *priv = spi_master_get_devdata(master); npcm_pspi_reset_hw(priv); clk_disable_unprepare(priv->clk); -- cgit v1.2.3 From 39be9b6d0455ed6dc6e9ac7252f56a498db5314e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 18:09:39 -0800 Subject: Input: soc_button_array - add usage-page 0x01 usage-id 0xca mapping The ACPI0011 _DSD button descriptor on a CHT based Intel Compute Sticks contains a mapping for usage-page 0x01 usage-id 0xca. As described in hutrr52_system_display_rotation_lock_controls_0.pdf this should be mapped as a "System Display Rotation Lock Slider Switch", this commit adds support for this, silencing the following warning: soc_button_array ACPI0011:00: Unknown button index 4 upage 01 usage ca, ignoring Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index 23520df7650f..f53923b1593b 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -185,6 +185,10 @@ static int soc_button_parse_btn_desc(struct device *dev, info->name = "power"; info->event_code = KEY_POWER; info->wakeup = true; + } else if (upage == 0x01 && usage == 0xca) { + info->name = "rotation lock switch"; + info->event_type = EV_SW; + info->event_code = SW_ROTATE_LOCK; } else if (upage == 0x07 && usage == 0xe3) { info->name = "home"; info->event_code = KEY_LEFTMETA; -- cgit v1.2.3 From e9eb788f9442d1b5d93efdb30c3be071ce8a22b1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 18:10:45 -0800 Subject: Input: soc_button_array - fix mapping of the 5th GPIO in a PNP0C40 device The Microsoft documenation for the PNP0C40 device aka the "Windows-compatible button array" describes the 5th GpioInt listed in the resources as: '5. Interrupt corresponding to the "Rotation Lock" button, if supported'. Notice this describes the 5th entry as a button while we sofar have been mapping it to EV_SW, SW_ROTATE_LOCK. On my Point of View TAB P1006W-232 which actually comes with a rotation-lock button, the button indeed is a button and not a slider/switch. An image search for other Windows tablets has found 2 more models with a rotation-lock button and on both of those it too is a push-button and not a slider/switch. Further evidence can be found in the HUT extension HUTRR52 from Microsoft which adds rotation lock support to the HUT, which describes 2 different usages: "0xC9 System Display Rotation Lock Button" and "0xCA System Display Rotation Lock Slider Switch" note that switch is seen as a separate thing here and the non switch wording is an exact match for the "Windows-compatible button array" spec wording. TL;DR: our current mapping of the 5th GPIO to SW_ROTATE_LOCK is wrong because the 5th GPIO is for a push-button not a switch. This commit fixes this by maping the 5th GPIO to KEY_ROTATE_LOCK_TOGGLE. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index f53923b1593b..bb458beecb43 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -377,7 +377,7 @@ static struct soc_button_info soc_button_PNP0C40[] = { { "home", 1, EV_KEY, KEY_LEFTMETA, false, true }, { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false }, { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false }, - { "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false }, + { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false }, { } }; -- cgit v1.2.3 From c546d49656143855093c7b7fde60866e6e23a69d Mon Sep 17 00:00:00 2001 From: Tomasz Duszynski Date: Tue, 18 Dec 2018 21:28:09 +0100 Subject: iio: chemical: sps30: add support for self cleaning Self cleaning is especially useful in cases where sensor undergoes frequent power on/off cycles. In such scenarios it is recommended to turn self cleaning at least once per week in order to maintain reliable measurements. Self cleaning is activated by writing 1 to a dedicated attribute. Internal fan accelerates to its maximum speed and keeps spinning for about 10 seconds blowing out accumulated dust. Signed-off-by: Tomasz Duszynski Tested-by: Andreas Brauchli Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/sps30.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index fa3cd409b90b..f3b4390c8f5c 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -7,7 +7,6 @@ * I2C slave address: 0x69 * * TODO: - * - support for turning on fan cleaning * - support for reading/setting auto cleaning interval */ @@ -37,6 +36,7 @@ #define SPS30_READ_DATA_READY_FLAG 0x0202 #define SPS30_READ_DATA 0x0300 #define SPS30_READ_SERIAL 0xd033 +#define SPS30_START_FAN_CLEANING 0x5607 enum { PM1, @@ -104,6 +104,7 @@ static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size) break; case SPS30_STOP_MEAS: case SPS30_RESET: + case SPS30_START_FAN_CLEANING: ret = sps30_write_then_read(state, buf, 2, NULL, 0); break; case SPS30_READ_DATA_READY_FLAG: @@ -275,7 +276,39 @@ static int sps30_read_raw(struct iio_dev *indio_dev, return -EINVAL; } +static ssize_t start_cleaning_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sps30_state *state = iio_priv(indio_dev); + int val, ret; + + if (kstrtoint(buf, 0, &val) || val != 1) + return -EINVAL; + + mutex_lock(&state->lock); + ret = sps30_do_cmd(state, SPS30_START_FAN_CLEANING, NULL, 0); + mutex_unlock(&state->lock); + if (ret) + return ret; + + return len; +} + +static IIO_DEVICE_ATTR_WO(start_cleaning, 0); + +static struct attribute *sps30_attrs[] = { + &iio_dev_attr_start_cleaning.dev_attr.attr, + NULL +}; + +static const struct attribute_group sps30_attr_group = { + .attrs = sps30_attrs, +}; + static const struct iio_info sps30_info = { + .attrs = &sps30_attr_group, .read_raw = sps30_read_raw, }; -- cgit v1.2.3 From ae0b3773721f08526c850e2d8dec85bdb870cd12 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Thu, 20 Dec 2018 01:21:22 -0600 Subject: iio: ad9523: fix a missing check of return value If ad9523_write() fails, indio_dev may get incorrect data. The fix inserts a check for the return value of ad9523_write(), and it fails, returns an error. Signed-off-by: Kangjie Lu Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/ad9523.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index f3f94fbdd20a..3f9be69499ec 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -943,11 +943,14 @@ static int ad9523_setup(struct iio_dev *indio_dev) } } - for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN) - ad9523_write(indio_dev, + for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN) { + ret = ad9523_write(indio_dev, AD9523_CHANNEL_CLOCK_DIST(i), AD9523_CLK_DIST_DRIVER_MODE(TRISTATE) | AD9523_CLK_DIST_PWR_DOWN_EN); + if (ret < 0) + return ret; + } ret = ad9523_write(indio_dev, AD9523_POWER_DOWN_CTRL, 0); if (ret < 0) -- cgit v1.2.3 From 2bbf53e3e50661c0383048b86a387f74ce6b023c Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Mon, 17 Dec 2018 14:23:35 +0200 Subject: staging: iio: adc: ad7606: Simplify the Kconfing menu There is no point in having three menu entries that can be selected individually. Instead, the SPI and parallel interfaces should select AD7606. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/Kconfig | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index fc23059f1673..302639ab9c89 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -4,35 +4,28 @@ menu "Analog to digital converters" config AD7606 - tristate "Analog Devices AD7606 ADC driver" - depends on GPIOLIB || COMPILE_TEST - depends on HAS_IOMEM + tristate select IIO_BUFFER select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices: - ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). - - To compile this driver as a module, choose M here: the - module will be called ad7606. config AD7606_IFACE_PARALLEL - tristate "parallel interface support" - depends on AD7606 + tristate "Analog Devices AD7606 ADC driver with parallel interface support" + depends on HAS_IOMEM + select AD7606 help - Say yes here to include parallel interface support on the AD7606 - ADC driver. + Say yes here to build parallel interface support for Analog Devices: + ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). To compile this driver as a module, choose M here: the module will be called ad7606_parallel. config AD7606_IFACE_SPI - tristate "spi interface support" - depends on AD7606 + tristate "Analog Devices AD7606 ADC driver with spi interface support" depends on SPI + select AD7606 help - Say yes here to include parallel interface support on the AD7606 - ADC driver. + Say yes here to build spi interface support for Analog Devices: + ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). To compile this driver as a module, choose M here: the module will be called ad7606_spi. -- cgit v1.2.3 From ca5b4637d7ca561dbaba13d725957610a783ac2c Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Mon, 17 Dec 2018 14:23:36 +0200 Subject: staging: iio: adc: ad7606: Use SPDX identifier This patch replaces the license text at the top of ad7606 driver files and instead adds SPDX GPL-2.0 license identifier. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 3 +-- drivers/staging/iio/adc/ad7606.h | 3 +-- drivers/staging/iio/adc/ad7606_par.c | 3 +-- drivers/staging/iio/adc/ad7606_spi.c | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index e1d85b7a0e4c..8a34efa6c0f8 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * AD7606 SPI ADC driver * * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. */ #include diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 510a93db362f..3e12fff2f1ad 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -1,9 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * AD7606 ADC driver * * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. */ #ifndef IIO_ADC_AD7606_H_ diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index da26742e8b46..ae0867fd4b99 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * AD7606 Parallel Interface ADC driver * * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. */ #include diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index e533917db094..a69c26537a47 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * AD7606 SPI ADC driver * * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. */ #include -- cgit v1.2.3 From cc49bd1652a405dc641aeffa6b0925ad9a1affb3 Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Mon, 17 Dec 2018 14:23:37 +0200 Subject: staging: iio: adc: ad7606: Add support for threaded irq This patch replaces the use of a polling ring buffer with a threaded interrupt. Enabling the buffer sets the CONVST signal to high. When the rising edge of the CONVST is applied, BUSY signal goes logic high and transitions low at the end of the entire conversion process. The falling edge of the BUSY signal triggers the interrupt. ad7606_trigger_handler() is used as bottom half of the poll function. It reads data from the device and stores it in the internal buffer. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 111 +++++++++++++++++++++++++++++---------- drivers/staging/iio/adc/ad7606.h | 6 +-- 2 files changed, 84 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 8a34efa6c0f8..50d88571e4ac 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "ad7606.h" @@ -86,36 +87,24 @@ static int ad7606_read_samples(struct ad7606_state *st) static irqreturn_t ad7606_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; - struct ad7606_state *st = iio_priv(pf->indio_dev); - - gpiod_set_value(st->gpio_convst, 1); - - return IRQ_HANDLED; -} - -/** - * ad7606_poll_bh_to_ring() bh of trigger launched polling to ring buffer - * @work_s: the work struct through which this was scheduled - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - * I think the one copy of this at a time was to avoid problems if the - * trigger was set far too high and the reads then locked up the computer. - **/ -static void ad7606_poll_bh_to_ring(struct work_struct *work_s) -{ - struct ad7606_state *st = container_of(work_s, struct ad7606_state, - poll_work); - struct iio_dev *indio_dev = iio_priv_to_dev(st); + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7606_state *st = iio_priv(indio_dev); int ret; + mutex_lock(&st->lock); + ret = ad7606_read_samples(st); if (ret == 0) iio_push_to_buffers_with_timestamp(indio_dev, st->data, iio_get_time_ns(indio_dev)); - gpiod_set_value(st->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); + /* The rising edge of the CONVST signal starts a new conversion. */ + gpiod_set_value(st->gpio_convst, 1); + + mutex_unlock(&st->lock); + + return IRQ_HANDLED; } static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) @@ -366,8 +355,11 @@ static int ad7606_request_gpios(struct ad7606_state *st) return PTR_ERR_OR_ZERO(st->gpio_os); } -/** - * Interrupt handler +/* + * The BUSY signal indicates when conversions are in progress, so when a rising + * edge of CONVST is applied, BUSY goes logic high and transitions low at the + * end of the entire conversion process. The falling edge of the BUSY signal + * triggers this interrupt. */ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) { @@ -375,7 +367,8 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) struct ad7606_state *st = iio_priv(indio_dev); if (iio_buffer_enabled(indio_dev)) { - schedule_work(&st->poll_work); + gpiod_set_value(st->gpio_convst, 0); + iio_trigger_poll_chained(st->trig); } else { complete(&st->completion); } @@ -383,26 +376,69 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) return IRQ_HANDLED; }; +static int ad7606_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + if (st->trig != trig) + return -EINVAL; + + return 0; +} + +static int ad7606_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + iio_triggered_buffer_postenable(indio_dev); + gpiod_set_value(st->gpio_convst, 1); + + return 0; +} + +static int ad7606_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + gpiod_set_value(st->gpio_convst, 0); + + return iio_triggered_buffer_predisable(indio_dev); +} + +static const struct iio_buffer_setup_ops ad7606_buffer_ops = { + .postenable = &ad7606_buffer_postenable, + .predisable = &ad7606_buffer_predisable, +}; + static const struct iio_info ad7606_info_no_os_or_range = { .read_raw = &ad7606_read_raw, + .validate_trigger = &ad7606_validate_trigger, }; static const struct iio_info ad7606_info_os_and_range = { .read_raw = &ad7606_read_raw, .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os_and_range, + .validate_trigger = &ad7606_validate_trigger, }; static const struct iio_info ad7606_info_os = { .read_raw = &ad7606_read_raw, .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os, + .validate_trigger = &ad7606_validate_trigger, }; static const struct iio_info ad7606_info_range = { .read_raw = &ad7606_read_raw, .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_range, + .validate_trigger = &ad7606_validate_trigger, +}; + +static const struct iio_trigger_ops ad7606_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, }; static void ad7606_regulator_disable(void *data) @@ -434,7 +470,6 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, /* tied to logic low, analog input range is +/- 5V */ st->range = 0; st->oversampling = 1; - INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); st->reg = devm_regulator_get(dev, "avcc"); if (IS_ERR(st->reg)) @@ -479,14 +514,32 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); - ret = devm_request_irq(dev, irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, - name, indio_dev); + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7606_trigger_ops; + st->trig->dev.parent = dev; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + ret = devm_request_threaded_irq(dev, irq, + NULL, + &ad7606_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + name, indio_dev); if (ret) return ret; ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, &ad7606_trigger_handler, - NULL, NULL); + &ad7606_buffer_ops); if (ret) return ret; diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 3e12fff2f1ad..9a832d208acf 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -26,8 +26,6 @@ struct ad7606_chip_info { * @dev pointer to kernel device * @chip_info entry in the table of chips that describes this device * @reg regulator info for the the power supply of the device - * @poll_work work struct for continuously reading data from the device - * into an IIO triggered buffer * @bops bus operations (SPI or parallel) * @range voltage range selection, selects which scale to apply * @oversampling oversampling selection @@ -42,14 +40,13 @@ struct ad7606_chip_info { * is being read on the first channel * @gpio_os GPIO descriptors to control oversampling on the device * @complete completion to indicate end of conversion + * @trig The IIO trigger associated with the device. * @data buffer for reading data from the device */ - struct ad7606_state { struct device *dev; const struct ad7606_chip_info *chip_info; struct regulator *reg; - struct work_struct poll_work; const struct ad7606_bus_ops *bops; unsigned int range; unsigned int oversampling; @@ -62,6 +59,7 @@ struct ad7606_state { struct gpio_desc *gpio_standby; struct gpio_desc *gpio_frstdata; struct gpio_descs *gpio_os; + struct iio_trigger *trig; struct completion completion; /* -- cgit v1.2.3 From 54160ae3b2d3b45824da90a64d81c9a148c6fdbf Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Mon, 17 Dec 2018 14:23:38 +0200 Subject: staging: iio: adc: ad7606: Misc style fixes (no functional change) * Placed includes in alphabetical order * Added brackets around num and mask through out for AD760X_CHANNEL * Used single line comments where needed * Removed extra lines and spaces Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606.c | 27 ++++++++++++--------------- drivers/staging/iio/adc/ad7606.h | 1 - drivers/staging/iio/adc/ad7606_par.c | 27 ++++++++------------------- drivers/staging/iio/adc/ad7606_spi.c | 16 ++++++++-------- 4 files changed, 28 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 50d88571e4ac..ebb8de03bbce 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -5,25 +5,25 @@ * Copyright 2011 Analog Devices Inc. */ -#include +#include #include -#include -#include -#include -#include #include #include -#include -#include +#include +#include #include +#include +#include +#include +#include #include #include -#include #include -#include +#include #include #include +#include #include "ad7606.h" @@ -249,8 +249,7 @@ static const struct attribute_group ad7606_attribute_group_range = { .attrs = ad7606_attributes_range, }; -#define AD760X_CHANNEL(num, mask) \ - { \ +#define AD760X_CHANNEL(num, mask) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = num, \ @@ -265,7 +264,7 @@ static const struct attribute_group ad7606_attribute_group_range = { .storagebits = 16, \ .endianness = IIO_CPU, \ }, \ - } +} #define AD7605_CHANNEL(num) \ AD760X_CHANNEL(num, 0) @@ -294,9 +293,7 @@ static const struct iio_chan_spec ad7606_channels[] = { }; static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { - /* - * More devices added in future - */ + /* More devices added in future */ [ID_AD7605_4] = { .channels = ad7605_channels, .num_channels = 5, diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 9a832d208acf..5d12410f68e1 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -14,7 +14,6 @@ * @num_channels: number of channels * @has_oversampling: whether the device has oversampling support */ - struct ad7606_chip_info { const struct iio_chan_spec *channels; unsigned int num_channels; diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index ae0867fd4b99..1b08028facde 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -26,7 +26,7 @@ static int ad7606_par16_read_block(struct device *dev, } static const struct ad7606_bus_ops ad7606_par16_bops = { - .read_block = ad7606_par16_read_block, + .read_block = ad7606_par16_read_block, }; static int ad7606_par8_read_block(struct device *dev, @@ -41,7 +41,7 @@ static int ad7606_par8_read_block(struct device *dev, } static const struct ad7606_bus_ops ad7606_par8_bops = { - .read_block = ad7606_par8_read_block, + .read_block = ad7606_par8_read_block, }; static int ad7606_par_probe(struct platform_device *pdev) @@ -72,22 +72,12 @@ static int ad7606_par_probe(struct platform_device *pdev) } static const struct platform_device_id ad7606_driver_ids[] = { - { - .name = "ad7605-4", - .driver_data = ID_AD7605_4, - }, { - .name = "ad7606-8", - .driver_data = ID_AD7606_8, - }, { - .name = "ad7606-6", - .driver_data = ID_AD7606_6, - }, { - .name = "ad7606-4", - .driver_data = ID_AD7606_4, - }, + { .name = "ad7605-4", .driver_data = ID_AD7605_4, }, + { .name = "ad7606-4", .driver_data = ID_AD7606_4, }, + { .name = "ad7606-6", .driver_data = ID_AD7606_6, }, + { .name = "ad7606-8", .driver_data = ID_AD7606_8, }, { } }; - MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); static const struct of_device_id ad7606_of_match[] = { @@ -103,12 +93,11 @@ static struct platform_driver ad7606_driver = { .probe = ad7606_par_probe, .id_table = ad7606_driver_ids, .driver = { - .name = "ad7606", - .pm = AD7606_PM_OPS, + .name = "ad7606", + .pm = AD7606_PM_OPS, .of_match_table = ad7606_of_match, }, }; - module_platform_driver(ad7606_driver); MODULE_AUTHOR("Michael Hennerich "); diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index a69c26537a47..4fd0ec36a086 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -36,7 +36,7 @@ static int ad7606_spi_read_block(struct device *dev, } static const struct ad7606_bus_ops ad7606_spi_bops = { - .read_block = ad7606_spi_read_block, + .read_block = ad7606_spi_read_block, }; static int ad7606_spi_probe(struct spi_device *spi) @@ -48,14 +48,14 @@ static int ad7606_spi_probe(struct spi_device *spi) &ad7606_spi_bops); } -static const struct spi_device_id ad7606_id[] = { - {"ad7605-4", ID_AD7605_4}, - {"ad7606-8", ID_AD7606_8}, - {"ad7606-6", ID_AD7606_6}, - {"ad7606-4", ID_AD7606_4}, +static const struct spi_device_id ad7606_id_table[] = { + { "ad7605-4", ID_AD7605_4 }, + { "ad7606-4", ID_AD7606_4 }, + { "ad7606-6", ID_AD7606_6 }, + { "ad7606-8", ID_AD7606_8 }, {} }; -MODULE_DEVICE_TABLE(spi, ad7606_id); +MODULE_DEVICE_TABLE(spi, ad7606_id_table); static const struct of_device_id ad7606_of_match[] = { { .compatible = "adi,ad7605-4" }, @@ -73,7 +73,7 @@ static struct spi_driver ad7606_driver = { .pm = AD7606_PM_OPS, }, .probe = ad7606_spi_probe, - .id_table = ad7606_id, + .id_table = ad7606_id_table, }; module_spi_driver(ad7606_driver); -- cgit v1.2.3 From 2985a5d88455a3edd51358fc77f61b684d0e9265 Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Mon, 17 Dec 2018 14:23:39 +0200 Subject: staging: iio: adc: ad7606: Move out of staging Move ad7606 ADC driver out of staging and into the mainline. Signed-off-by: Stefan Popa Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 27 ++ drivers/iio/adc/Makefile | 3 + drivers/iio/adc/ad7606.c | 583 +++++++++++++++++++++++++++++++++++ drivers/iio/adc/ad7606.h | 99 ++++++ drivers/iio/adc/ad7606_par.c | 105 +++++++ drivers/iio/adc/ad7606_spi.c | 82 +++++ drivers/staging/iio/adc/Kconfig | 27 -- drivers/staging/iio/adc/Makefile | 4 - drivers/staging/iio/adc/ad7606.c | 583 ----------------------------------- drivers/staging/iio/adc/ad7606.h | 99 ------ drivers/staging/iio/adc/ad7606_par.c | 105 ------- drivers/staging/iio/adc/ad7606_spi.c | 82 ----- 12 files changed, 899 insertions(+), 900 deletions(-) create mode 100644 drivers/iio/adc/ad7606.c create mode 100644 drivers/iio/adc/ad7606.h create mode 100644 drivers/iio/adc/ad7606_par.c create mode 100644 drivers/iio/adc/ad7606_spi.c delete mode 100644 drivers/staging/iio/adc/ad7606.c delete mode 100644 drivers/staging/iio/adc/ad7606.h delete mode 100644 drivers/staging/iio/adc/ad7606_par.c delete mode 100644 drivers/staging/iio/adc/ad7606_spi.c (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7a3ca4ec0cb7..f3cc7a31bce5 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -69,6 +69,33 @@ config AD7476 To compile this driver as a module, choose M here: the module will be called ad7476. +config AD7606 + tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + +config AD7606_IFACE_PARALLEL + tristate "Analog Devices AD7606 ADC driver with parallel interface support" + depends on HAS_IOMEM + select AD7606 + help + Say yes here to build parallel interface support for Analog Devices: + ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). + + To compile this driver as a module, choose M here: the + module will be called ad7606_parallel. + +config AD7606_IFACE_SPI + tristate "Analog Devices AD7606 ADC driver with spi interface support" + depends on SPI + select AD7606 + help + Say yes here to build spi interface support for Analog Devices: + ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). + + To compile this driver as a module, choose M here: the + module will be called ad7606_spi. + config AD7766 tristate "Analog Devices AD7766/AD7767 ADC driver" depends on SPI_MASTER diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 07df37f621bd..ea5031348052 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -11,6 +11,9 @@ obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7923) += ad7923.o obj-$(CONFIG_AD7476) += ad7476.o +obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o +obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o +obj-$(CONFIG_AD7606) += ad7606.o obj-$(CONFIG_AD7766) += ad7766.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c new file mode 100644 index 000000000000..ebb8de03bbce --- /dev/null +++ b/drivers/iio/adc/ad7606.c @@ -0,0 +1,583 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7606 SPI ADC driver + * + * Copyright 2011 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ad7606.h" + +/* + * Scales are computed as 5000/32768 and 10000/32768 respectively, + * so that when applied to the raw values they provide mV values + */ +static const unsigned int scale_avail[2] = { + 152588, 305176 +}; + +static const unsigned int ad7606_oversampling_avail[7] = { + 1, 2, 4, 8, 16, 32, 64, +}; + +static int ad7606_reset(struct ad7606_state *st) +{ + if (st->gpio_reset) { + gpiod_set_value(st->gpio_reset, 1); + ndelay(100); /* t_reset >= 100ns */ + gpiod_set_value(st->gpio_reset, 0); + return 0; + } + + return -ENODEV; +} + +static int ad7606_read_samples(struct ad7606_state *st) +{ + unsigned int num = st->chip_info->num_channels; + u16 *data = st->data; + int ret; + + /* + * The frstdata signal is set to high while and after reading the sample + * of the first channel and low for all other channels. This can be used + * to check that the incoming data is correctly aligned. During normal + * operation the data should never become unaligned, but some glitch or + * electrostatic discharge might cause an extra read or clock cycle. + * Monitoring the frstdata signal allows to recover from such failure + * situations. + */ + + if (st->gpio_frstdata) { + ret = st->bops->read_block(st->dev, 1, data); + if (ret) + return ret; + + if (!gpiod_get_value(st->gpio_frstdata)) { + ad7606_reset(st); + return -EIO; + } + + data++; + num--; + } + + return st->bops->read_block(st->dev, num, data); +} + +static irqreturn_t ad7606_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7606_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + + ret = ad7606_read_samples(st); + if (ret == 0) + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_get_time_ns(indio_dev)); + + iio_trigger_notify_done(indio_dev->trig); + /* The rising edge of the CONVST signal starts a new conversion. */ + gpiod_set_value(st->gpio_convst, 1); + + mutex_unlock(&st->lock); + + return IRQ_HANDLED; +} + +static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) +{ + struct ad7606_state *st = iio_priv(indio_dev); + int ret; + + gpiod_set_value(st->gpio_convst, 1); + ret = wait_for_completion_timeout(&st->completion, + msecs_to_jiffies(1000)); + if (!ret) { + ret = -ETIMEDOUT; + goto error_ret; + } + + ret = ad7606_read_samples(st); + if (ret == 0) + ret = st->data[ch]; + +error_ret: + gpiod_set_value(st->gpio_convst, 0); + + return ret; +} + +static int ad7606_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + int ret; + struct ad7606_state *st = iio_priv(indio_dev); + + switch (m) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = ad7606_scan_direct(indio_dev, chan->address); + iio_device_release_direct_mode(indio_dev); + + if (ret < 0) + return ret; + *val = (short)ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = scale_avail[st->range]; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling; + return IIO_VAL_INT; + } + return -EINVAL; +} + +static ssize_t in_voltage_scale_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i, len = 0; + + for (i = 0; i < ARRAY_SIZE(scale_avail); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", + scale_avail[i]); + + buf[len - 1] = '\n'; + + return len; +} + +static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); + +static int ad7606_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ad7606_state *st = iio_priv(indio_dev); + DECLARE_BITMAP(values, 3); + int i; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + mutex_lock(&st->lock); + i = find_closest(val2, scale_avail, ARRAY_SIZE(scale_avail)); + gpiod_set_value(st->gpio_range, i); + st->range = i; + mutex_unlock(&st->lock); + + return 0; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val2) + return -EINVAL; + i = find_closest(val, ad7606_oversampling_avail, + ARRAY_SIZE(ad7606_oversampling_avail)); + + values[0] = i; + + mutex_lock(&st->lock); + gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, + st->gpio_os->info, values); + st->oversampling = ad7606_oversampling_avail[i]; + mutex_unlock(&st->lock); + + return 0; + default: + return -EINVAL; + } +} + +static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64"); + +static struct attribute *ad7606_attributes_os_and_range[] = { + &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, + &iio_const_attr_oversampling_ratio_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7606_attribute_group_os_and_range = { + .attrs = ad7606_attributes_os_and_range, +}; + +static struct attribute *ad7606_attributes_os[] = { + &iio_const_attr_oversampling_ratio_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7606_attribute_group_os = { + .attrs = ad7606_attributes_os, +}; + +static struct attribute *ad7606_attributes_range[] = { + &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7606_attribute_group_range = { + .attrs = ad7606_attributes_range, +}; + +#define AD760X_CHANNEL(num, mask) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = num, \ + .address = num, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ + .info_mask_shared_by_all = mask, \ + .scan_index = num, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define AD7605_CHANNEL(num) \ + AD760X_CHANNEL(num, 0) + +#define AD7606_CHANNEL(num) \ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) + +static const struct iio_chan_spec ad7605_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(4), + AD7605_CHANNEL(0), + AD7605_CHANNEL(1), + AD7605_CHANNEL(2), + AD7605_CHANNEL(3), +}; + +static const struct iio_chan_spec ad7606_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0), + AD7606_CHANNEL(1), + AD7606_CHANNEL(2), + AD7606_CHANNEL(3), + AD7606_CHANNEL(4), + AD7606_CHANNEL(5), + AD7606_CHANNEL(6), + AD7606_CHANNEL(7), +}; + +static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { + /* More devices added in future */ + [ID_AD7605_4] = { + .channels = ad7605_channels, + .num_channels = 5, + }, + [ID_AD7606_8] = { + .channels = ad7606_channels, + .num_channels = 9, + .has_oversampling = true, + }, + [ID_AD7606_6] = { + .channels = ad7606_channels, + .num_channels = 7, + .has_oversampling = true, + }, + [ID_AD7606_4] = { + .channels = ad7606_channels, + .num_channels = 5, + .has_oversampling = true, + }, +}; + +static int ad7606_request_gpios(struct ad7606_state *st) +{ + struct device *dev = st->dev; + + st->gpio_convst = devm_gpiod_get(dev, "adi,conversion-start", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_convst)) + return PTR_ERR(st->gpio_convst); + + st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); + + st->gpio_range = devm_gpiod_get_optional(dev, "adi,range", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_range)) + return PTR_ERR(st->gpio_range); + + st->gpio_standby = devm_gpiod_get_optional(dev, "standby", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_standby)) + return PTR_ERR(st->gpio_standby); + + st->gpio_frstdata = devm_gpiod_get_optional(dev, "adi,first-data", + GPIOD_IN); + if (IS_ERR(st->gpio_frstdata)) + return PTR_ERR(st->gpio_frstdata); + + if (!st->chip_info->has_oversampling) + return 0; + + st->gpio_os = devm_gpiod_get_array_optional(dev, + "adi,oversampling-ratio", + GPIOD_OUT_LOW); + return PTR_ERR_OR_ZERO(st->gpio_os); +} + +/* + * The BUSY signal indicates when conversions are in progress, so when a rising + * edge of CONVST is applied, BUSY goes logic high and transitions low at the + * end of the entire conversion process. The falling edge of the BUSY signal + * triggers this interrupt. + */ +static irqreturn_t ad7606_interrupt(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct ad7606_state *st = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev)) { + gpiod_set_value(st->gpio_convst, 0); + iio_trigger_poll_chained(st->trig); + } else { + complete(&st->completion); + } + + return IRQ_HANDLED; +}; + +static int ad7606_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + if (st->trig != trig) + return -EINVAL; + + return 0; +} + +static int ad7606_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + iio_triggered_buffer_postenable(indio_dev); + gpiod_set_value(st->gpio_convst, 1); + + return 0; +} + +static int ad7606_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + gpiod_set_value(st->gpio_convst, 0); + + return iio_triggered_buffer_predisable(indio_dev); +} + +static const struct iio_buffer_setup_ops ad7606_buffer_ops = { + .postenable = &ad7606_buffer_postenable, + .predisable = &ad7606_buffer_predisable, +}; + +static const struct iio_info ad7606_info_no_os_or_range = { + .read_raw = &ad7606_read_raw, + .validate_trigger = &ad7606_validate_trigger, +}; + +static const struct iio_info ad7606_info_os_and_range = { + .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, + .attrs = &ad7606_attribute_group_os_and_range, + .validate_trigger = &ad7606_validate_trigger, +}; + +static const struct iio_info ad7606_info_os = { + .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, + .attrs = &ad7606_attribute_group_os, + .validate_trigger = &ad7606_validate_trigger, +}; + +static const struct iio_info ad7606_info_range = { + .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, + .attrs = &ad7606_attribute_group_range, + .validate_trigger = &ad7606_validate_trigger, +}; + +static const struct iio_trigger_ops ad7606_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static void ad7606_regulator_disable(void *data) +{ + struct ad7606_state *st = data; + + regulator_disable(st->reg); +} + +int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, + const char *name, unsigned int id, + const struct ad7606_bus_ops *bops) +{ + struct ad7606_state *st; + int ret; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + + st->dev = dev; + mutex_init(&st->lock); + st->bops = bops; + st->base_address = base_address; + /* tied to logic low, analog input range is +/- 5V */ + st->range = 0; + st->oversampling = 1; + + st->reg = devm_regulator_get(dev, "avcc"); + if (IS_ERR(st->reg)) + return PTR_ERR(st->reg); + + ret = regulator_enable(st->reg); + if (ret) { + dev_err(dev, "Failed to enable specified AVcc supply\n"); + return ret; + } + + ret = devm_add_action_or_reset(dev, ad7606_regulator_disable, st); + if (ret) + return ret; + + st->chip_info = &ad7606_chip_info_tbl[id]; + + ret = ad7606_request_gpios(st); + if (ret) + return ret; + + indio_dev->dev.parent = dev; + if (st->gpio_os) { + if (st->gpio_range) + indio_dev->info = &ad7606_info_os_and_range; + else + indio_dev->info = &ad7606_info_os; + } else { + if (st->gpio_range) + indio_dev->info = &ad7606_info_range; + else + indio_dev->info = &ad7606_info_no_os_or_range; + } + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = name; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + + init_completion(&st->completion); + + ret = ad7606_reset(st); + if (ret) + dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); + + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7606_trigger_ops; + st->trig->dev.parent = dev; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + ret = devm_request_threaded_irq(dev, irq, + NULL, + &ad7606_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + name, indio_dev); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &ad7606_trigger_handler, + &ad7606_buffer_ops); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_GPL(ad7606_probe); + +#ifdef CONFIG_PM_SLEEP + +static int ad7606_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + if (st->gpio_standby) { + gpiod_set_value(st->gpio_range, 1); + gpiod_set_value(st->gpio_standby, 0); + } + + return 0; +} + +static int ad7606_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + if (st->gpio_standby) { + gpiod_set_value(st->gpio_range, st->range); + gpiod_set_value(st->gpio_standby, 1); + ad7606_reset(st); + } + + return 0; +} + +SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume); +EXPORT_SYMBOL_GPL(ad7606_pm_ops); + +#endif + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h new file mode 100644 index 000000000000..5d12410f68e1 --- /dev/null +++ b/drivers/iio/adc/ad7606.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AD7606 ADC driver + * + * Copyright 2011 Analog Devices Inc. + */ + +#ifndef IIO_ADC_AD7606_H_ +#define IIO_ADC_AD7606_H_ + +/** + * struct ad7606_chip_info - chip specific information + * @channels: channel specification + * @num_channels: number of channels + * @has_oversampling: whether the device has oversampling support + */ +struct ad7606_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; + bool has_oversampling; +}; + +/** + * struct ad7606_state - driver instance specific data + * @dev pointer to kernel device + * @chip_info entry in the table of chips that describes this device + * @reg regulator info for the the power supply of the device + * @bops bus operations (SPI or parallel) + * @range voltage range selection, selects which scale to apply + * @oversampling oversampling selection + * @base_address address from where to read data in parallel operation + * @lock protect sensor state from concurrent accesses to GPIOs + * @gpio_convst GPIO descriptor for conversion start signal (CONVST) + * @gpio_reset GPIO descriptor for device hard-reset + * @gpio_range GPIO descriptor for range selection + * @gpio_standby GPIO descriptor for stand-by signal (STBY), + * controls power-down mode of device + * @gpio_frstdata GPIO descriptor for reading from device when data + * is being read on the first channel + * @gpio_os GPIO descriptors to control oversampling on the device + * @complete completion to indicate end of conversion + * @trig The IIO trigger associated with the device. + * @data buffer for reading data from the device + */ +struct ad7606_state { + struct device *dev; + const struct ad7606_chip_info *chip_info; + struct regulator *reg; + const struct ad7606_bus_ops *bops; + unsigned int range; + unsigned int oversampling; + void __iomem *base_address; + + struct mutex lock; /* protect sensor state */ + struct gpio_desc *gpio_convst; + struct gpio_desc *gpio_reset; + struct gpio_desc *gpio_range; + struct gpio_desc *gpio_standby; + struct gpio_desc *gpio_frstdata; + struct gpio_descs *gpio_os; + struct iio_trigger *trig; + struct completion completion; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * 8 * 16-bit samples + 64-bit timestamp + */ + unsigned short data[12] ____cacheline_aligned; +}; + +/** + * struct ad7606_bus_ops - driver bus operations + * @read_block function pointer for reading blocks of data + */ +struct ad7606_bus_ops { + /* more methods added in future? */ + int (*read_block)(struct device *dev, int num, void *data); +}; + +int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, + const char *name, unsigned int id, + const struct ad7606_bus_ops *bops); + +enum ad7606_supported_device_ids { + ID_AD7605_4, + ID_AD7606_8, + ID_AD7606_6, + ID_AD7606_4 +}; + +#ifdef CONFIG_PM_SLEEP +extern const struct dev_pm_ops ad7606_pm_ops; +#define AD7606_PM_OPS (&ad7606_pm_ops) +#else +#define AD7606_PM_OPS NULL +#endif + +#endif /* IIO_ADC_AD7606_H_ */ diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c new file mode 100644 index 000000000000..1b08028facde --- /dev/null +++ b/drivers/iio/adc/ad7606_par.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7606 Parallel Interface ADC driver + * + * Copyright 2011 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include + +#include +#include "ad7606.h" + +static int ad7606_par16_read_block(struct device *dev, + int count, void *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + insw((unsigned long)st->base_address, buf, count); + + return 0; +} + +static const struct ad7606_bus_ops ad7606_par16_bops = { + .read_block = ad7606_par16_read_block, +}; + +static int ad7606_par8_read_block(struct device *dev, + int count, void *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + insb((unsigned long)st->base_address, buf, count * 2); + + return 0; +} + +static const struct ad7606_bus_ops ad7606_par8_bops = { + .read_block = ad7606_par8_read_block, +}; + +static int ad7606_par_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + struct resource *res; + void __iomem *addr; + resource_size_t remap_size; + int irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq: %d\n", irq); + return irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(addr)) + return PTR_ERR(addr); + + remap_size = resource_size(res); + + return ad7606_probe(&pdev->dev, irq, addr, + id->name, id->driver_data, + remap_size > 1 ? &ad7606_par16_bops : + &ad7606_par8_bops); +} + +static const struct platform_device_id ad7606_driver_ids[] = { + { .name = "ad7605-4", .driver_data = ID_AD7605_4, }, + { .name = "ad7606-4", .driver_data = ID_AD7606_4, }, + { .name = "ad7606-6", .driver_data = ID_AD7606_6, }, + { .name = "ad7606-8", .driver_data = ID_AD7606_8, }, + { } +}; +MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); + +static const struct of_device_id ad7606_of_match[] = { + { .compatible = "adi,ad7605-4" }, + { .compatible = "adi,ad7606-4" }, + { .compatible = "adi,ad7606-6" }, + { .compatible = "adi,ad7606-8" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ad7606_of_match); + +static struct platform_driver ad7606_driver = { + .probe = ad7606_par_probe, + .id_table = ad7606_driver_ids, + .driver = { + .name = "ad7606", + .pm = AD7606_PM_OPS, + .of_match_table = ad7606_of_match, + }, +}; +module_platform_driver(ad7606_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c new file mode 100644 index 000000000000..4fd0ec36a086 --- /dev/null +++ b/drivers/iio/adc/ad7606_spi.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7606 SPI ADC driver + * + * Copyright 2011 Analog Devices Inc. + */ + +#include +#include +#include +#include + +#include +#include "ad7606.h" + +#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ + +static int ad7606_spi_read_block(struct device *dev, + int count, void *buf) +{ + struct spi_device *spi = to_spi_device(dev); + int i, ret; + unsigned short *data = buf; + __be16 *bdata = buf; + + ret = spi_read(spi, buf, count * 2); + if (ret < 0) { + dev_err(&spi->dev, "SPI read error\n"); + return ret; + } + + for (i = 0; i < count; i++) + data[i] = be16_to_cpu(bdata[i]); + + return 0; +} + +static const struct ad7606_bus_ops ad7606_spi_bops = { + .read_block = ad7606_spi_read_block, +}; + +static int ad7606_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + + return ad7606_probe(&spi->dev, spi->irq, NULL, + id->name, id->driver_data, + &ad7606_spi_bops); +} + +static const struct spi_device_id ad7606_id_table[] = { + { "ad7605-4", ID_AD7605_4 }, + { "ad7606-4", ID_AD7606_4 }, + { "ad7606-6", ID_AD7606_6 }, + { "ad7606-8", ID_AD7606_8 }, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7606_id_table); + +static const struct of_device_id ad7606_of_match[] = { + { .compatible = "adi,ad7605-4" }, + { .compatible = "adi,ad7606-4" }, + { .compatible = "adi,ad7606-6" }, + { .compatible = "adi,ad7606-8" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ad7606_of_match); + +static struct spi_driver ad7606_driver = { + .driver = { + .name = "ad7606", + .of_match_table = ad7606_of_match, + .pm = AD7606_PM_OPS, + }, + .probe = ad7606_spi_probe, + .id_table = ad7606_id_table, +}; +module_spi_driver(ad7606_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 302639ab9c89..7a93d3a5c113 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -3,33 +3,6 @@ # menu "Analog to digital converters" -config AD7606 - tristate - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - -config AD7606_IFACE_PARALLEL - tristate "Analog Devices AD7606 ADC driver with parallel interface support" - depends on HAS_IOMEM - select AD7606 - help - Say yes here to build parallel interface support for Analog Devices: - ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). - - To compile this driver as a module, choose M here: the - module will be called ad7606_parallel. - -config AD7606_IFACE_SPI - tristate "Analog Devices AD7606 ADC driver with spi interface support" - depends on SPI - select AD7606 - help - Say yes here to build spi interface support for Analog Devices: - ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). - - To compile this driver as a module, choose M here: the - module will be called ad7606_spi. - config AD7780 tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index ebe83c1ad362..7a421088ff82 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -3,10 +3,6 @@ # Makefile for industrial I/O ADC drivers # -obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o -obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o -obj-$(CONFIG_AD7606) += ad7606.o - obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7816) += ad7816.o obj-$(CONFIG_AD7192) += ad7192.o diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c deleted file mode 100644 index ebb8de03bbce..000000000000 --- a/drivers/staging/iio/adc/ad7606.c +++ /dev/null @@ -1,583 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * AD7606 SPI ADC driver - * - * Copyright 2011 Analog Devices Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "ad7606.h" - -/* - * Scales are computed as 5000/32768 and 10000/32768 respectively, - * so that when applied to the raw values they provide mV values - */ -static const unsigned int scale_avail[2] = { - 152588, 305176 -}; - -static const unsigned int ad7606_oversampling_avail[7] = { - 1, 2, 4, 8, 16, 32, 64, -}; - -static int ad7606_reset(struct ad7606_state *st) -{ - if (st->gpio_reset) { - gpiod_set_value(st->gpio_reset, 1); - ndelay(100); /* t_reset >= 100ns */ - gpiod_set_value(st->gpio_reset, 0); - return 0; - } - - return -ENODEV; -} - -static int ad7606_read_samples(struct ad7606_state *st) -{ - unsigned int num = st->chip_info->num_channels; - u16 *data = st->data; - int ret; - - /* - * The frstdata signal is set to high while and after reading the sample - * of the first channel and low for all other channels. This can be used - * to check that the incoming data is correctly aligned. During normal - * operation the data should never become unaligned, but some glitch or - * electrostatic discharge might cause an extra read or clock cycle. - * Monitoring the frstdata signal allows to recover from such failure - * situations. - */ - - if (st->gpio_frstdata) { - ret = st->bops->read_block(st->dev, 1, data); - if (ret) - return ret; - - if (!gpiod_get_value(st->gpio_frstdata)) { - ad7606_reset(st); - return -EIO; - } - - data++; - num--; - } - - return st->bops->read_block(st->dev, num, data); -} - -static irqreturn_t ad7606_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct ad7606_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->lock); - - ret = ad7606_read_samples(st); - if (ret == 0) - iio_push_to_buffers_with_timestamp(indio_dev, st->data, - iio_get_time_ns(indio_dev)); - - iio_trigger_notify_done(indio_dev->trig); - /* The rising edge of the CONVST signal starts a new conversion. */ - gpiod_set_value(st->gpio_convst, 1); - - mutex_unlock(&st->lock); - - return IRQ_HANDLED; -} - -static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) -{ - struct ad7606_state *st = iio_priv(indio_dev); - int ret; - - gpiod_set_value(st->gpio_convst, 1); - ret = wait_for_completion_timeout(&st->completion, - msecs_to_jiffies(1000)); - if (!ret) { - ret = -ETIMEDOUT; - goto error_ret; - } - - ret = ad7606_read_samples(st); - if (ret == 0) - ret = st->data[ch]; - -error_ret: - gpiod_set_value(st->gpio_convst, 0); - - return ret; -} - -static int ad7606_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - int ret; - struct ad7606_state *st = iio_priv(indio_dev); - - switch (m) { - case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = ad7606_scan_direct(indio_dev, chan->address); - iio_device_release_direct_mode(indio_dev); - - if (ret < 0) - return ret; - *val = (short)ret; - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = scale_avail[st->range]; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - *val = st->oversampling; - return IIO_VAL_INT; - } - return -EINVAL; -} - -static ssize_t in_voltage_scale_available_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int i, len = 0; - - for (i = 0; i < ARRAY_SIZE(scale_avail); i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", - scale_avail[i]); - - buf[len - 1] = '\n'; - - return len; -} - -static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); - -static int ad7606_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct ad7606_state *st = iio_priv(indio_dev); - DECLARE_BITMAP(values, 3); - int i; - - switch (mask) { - case IIO_CHAN_INFO_SCALE: - mutex_lock(&st->lock); - i = find_closest(val2, scale_avail, ARRAY_SIZE(scale_avail)); - gpiod_set_value(st->gpio_range, i); - st->range = i; - mutex_unlock(&st->lock); - - return 0; - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (val2) - return -EINVAL; - i = find_closest(val, ad7606_oversampling_avail, - ARRAY_SIZE(ad7606_oversampling_avail)); - - values[0] = i; - - mutex_lock(&st->lock); - gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, - st->gpio_os->info, values); - st->oversampling = ad7606_oversampling_avail[i]; - mutex_unlock(&st->lock); - - return 0; - default: - return -EINVAL; - } -} - -static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64"); - -static struct attribute *ad7606_attributes_os_and_range[] = { - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, - &iio_const_attr_oversampling_ratio_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7606_attribute_group_os_and_range = { - .attrs = ad7606_attributes_os_and_range, -}; - -static struct attribute *ad7606_attributes_os[] = { - &iio_const_attr_oversampling_ratio_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7606_attribute_group_os = { - .attrs = ad7606_attributes_os, -}; - -static struct attribute *ad7606_attributes_range[] = { - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7606_attribute_group_range = { - .attrs = ad7606_attributes_range, -}; - -#define AD760X_CHANNEL(num, mask) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = num, \ - .address = num, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ - .info_mask_shared_by_all = mask, \ - .scan_index = num, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ - .endianness = IIO_CPU, \ - }, \ -} - -#define AD7605_CHANNEL(num) \ - AD760X_CHANNEL(num, 0) - -#define AD7606_CHANNEL(num) \ - AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) - -static const struct iio_chan_spec ad7605_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(4), - AD7605_CHANNEL(0), - AD7605_CHANNEL(1), - AD7605_CHANNEL(2), - AD7605_CHANNEL(3), -}; - -static const struct iio_chan_spec ad7606_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0), - AD7606_CHANNEL(1), - AD7606_CHANNEL(2), - AD7606_CHANNEL(3), - AD7606_CHANNEL(4), - AD7606_CHANNEL(5), - AD7606_CHANNEL(6), - AD7606_CHANNEL(7), -}; - -static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { - /* More devices added in future */ - [ID_AD7605_4] = { - .channels = ad7605_channels, - .num_channels = 5, - }, - [ID_AD7606_8] = { - .channels = ad7606_channels, - .num_channels = 9, - .has_oversampling = true, - }, - [ID_AD7606_6] = { - .channels = ad7606_channels, - .num_channels = 7, - .has_oversampling = true, - }, - [ID_AD7606_4] = { - .channels = ad7606_channels, - .num_channels = 5, - .has_oversampling = true, - }, -}; - -static int ad7606_request_gpios(struct ad7606_state *st) -{ - struct device *dev = st->dev; - - st->gpio_convst = devm_gpiod_get(dev, "adi,conversion-start", - GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_convst)) - return PTR_ERR(st->gpio_convst); - - st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_reset)) - return PTR_ERR(st->gpio_reset); - - st->gpio_range = devm_gpiod_get_optional(dev, "adi,range", - GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_range)) - return PTR_ERR(st->gpio_range); - - st->gpio_standby = devm_gpiod_get_optional(dev, "standby", - GPIOD_OUT_HIGH); - if (IS_ERR(st->gpio_standby)) - return PTR_ERR(st->gpio_standby); - - st->gpio_frstdata = devm_gpiod_get_optional(dev, "adi,first-data", - GPIOD_IN); - if (IS_ERR(st->gpio_frstdata)) - return PTR_ERR(st->gpio_frstdata); - - if (!st->chip_info->has_oversampling) - return 0; - - st->gpio_os = devm_gpiod_get_array_optional(dev, - "adi,oversampling-ratio", - GPIOD_OUT_LOW); - return PTR_ERR_OR_ZERO(st->gpio_os); -} - -/* - * The BUSY signal indicates when conversions are in progress, so when a rising - * edge of CONVST is applied, BUSY goes logic high and transitions low at the - * end of the entire conversion process. The falling edge of the BUSY signal - * triggers this interrupt. - */ -static irqreturn_t ad7606_interrupt(int irq, void *dev_id) -{ - struct iio_dev *indio_dev = dev_id; - struct ad7606_state *st = iio_priv(indio_dev); - - if (iio_buffer_enabled(indio_dev)) { - gpiod_set_value(st->gpio_convst, 0); - iio_trigger_poll_chained(st->trig); - } else { - complete(&st->completion); - } - - return IRQ_HANDLED; -}; - -static int ad7606_validate_trigger(struct iio_dev *indio_dev, - struct iio_trigger *trig) -{ - struct ad7606_state *st = iio_priv(indio_dev); - - if (st->trig != trig) - return -EINVAL; - - return 0; -} - -static int ad7606_buffer_postenable(struct iio_dev *indio_dev) -{ - struct ad7606_state *st = iio_priv(indio_dev); - - iio_triggered_buffer_postenable(indio_dev); - gpiod_set_value(st->gpio_convst, 1); - - return 0; -} - -static int ad7606_buffer_predisable(struct iio_dev *indio_dev) -{ - struct ad7606_state *st = iio_priv(indio_dev); - - gpiod_set_value(st->gpio_convst, 0); - - return iio_triggered_buffer_predisable(indio_dev); -} - -static const struct iio_buffer_setup_ops ad7606_buffer_ops = { - .postenable = &ad7606_buffer_postenable, - .predisable = &ad7606_buffer_predisable, -}; - -static const struct iio_info ad7606_info_no_os_or_range = { - .read_raw = &ad7606_read_raw, - .validate_trigger = &ad7606_validate_trigger, -}; - -static const struct iio_info ad7606_info_os_and_range = { - .read_raw = &ad7606_read_raw, - .write_raw = &ad7606_write_raw, - .attrs = &ad7606_attribute_group_os_and_range, - .validate_trigger = &ad7606_validate_trigger, -}; - -static const struct iio_info ad7606_info_os = { - .read_raw = &ad7606_read_raw, - .write_raw = &ad7606_write_raw, - .attrs = &ad7606_attribute_group_os, - .validate_trigger = &ad7606_validate_trigger, -}; - -static const struct iio_info ad7606_info_range = { - .read_raw = &ad7606_read_raw, - .write_raw = &ad7606_write_raw, - .attrs = &ad7606_attribute_group_range, - .validate_trigger = &ad7606_validate_trigger, -}; - -static const struct iio_trigger_ops ad7606_trigger_ops = { - .validate_device = iio_trigger_validate_own_device, -}; - -static void ad7606_regulator_disable(void *data) -{ - struct ad7606_state *st = data; - - regulator_disable(st->reg); -} - -int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, - const char *name, unsigned int id, - const struct ad7606_bus_ops *bops) -{ - struct ad7606_state *st; - int ret; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - - st = iio_priv(indio_dev); - dev_set_drvdata(dev, indio_dev); - - st->dev = dev; - mutex_init(&st->lock); - st->bops = bops; - st->base_address = base_address; - /* tied to logic low, analog input range is +/- 5V */ - st->range = 0; - st->oversampling = 1; - - st->reg = devm_regulator_get(dev, "avcc"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); - - ret = regulator_enable(st->reg); - if (ret) { - dev_err(dev, "Failed to enable specified AVcc supply\n"); - return ret; - } - - ret = devm_add_action_or_reset(dev, ad7606_regulator_disable, st); - if (ret) - return ret; - - st->chip_info = &ad7606_chip_info_tbl[id]; - - ret = ad7606_request_gpios(st); - if (ret) - return ret; - - indio_dev->dev.parent = dev; - if (st->gpio_os) { - if (st->gpio_range) - indio_dev->info = &ad7606_info_os_and_range; - else - indio_dev->info = &ad7606_info_os; - } else { - if (st->gpio_range) - indio_dev->info = &ad7606_info_range; - else - indio_dev->info = &ad7606_info_no_os_or_range; - } - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = name; - indio_dev->channels = st->chip_info->channels; - indio_dev->num_channels = st->chip_info->num_channels; - - init_completion(&st->completion); - - ret = ad7606_reset(st); - if (ret) - dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); - - st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", - indio_dev->name, indio_dev->id); - if (!st->trig) - return -ENOMEM; - - st->trig->ops = &ad7606_trigger_ops; - st->trig->dev.parent = dev; - iio_trigger_set_drvdata(st->trig, indio_dev); - ret = devm_iio_trigger_register(dev, st->trig); - if (ret) - return ret; - - indio_dev->trig = iio_trigger_get(st->trig); - - ret = devm_request_threaded_irq(dev, irq, - NULL, - &ad7606_interrupt, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - name, indio_dev); - if (ret) - return ret; - - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, - &iio_pollfunc_store_time, - &ad7606_trigger_handler, - &ad7606_buffer_ops); - if (ret) - return ret; - - return devm_iio_device_register(dev, indio_dev); -} -EXPORT_SYMBOL_GPL(ad7606_probe); - -#ifdef CONFIG_PM_SLEEP - -static int ad7606_suspend(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - if (st->gpio_standby) { - gpiod_set_value(st->gpio_range, 1); - gpiod_set_value(st->gpio_standby, 0); - } - - return 0; -} - -static int ad7606_resume(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - if (st->gpio_standby) { - gpiod_set_value(st->gpio_range, st->range); - gpiod_set_value(st->gpio_standby, 1); - ad7606_reset(st); - } - - return 0; -} - -SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume); -EXPORT_SYMBOL_GPL(ad7606_pm_ops); - -#endif - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h deleted file mode 100644 index 5d12410f68e1..000000000000 --- a/drivers/staging/iio/adc/ad7606.h +++ /dev/null @@ -1,99 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * AD7606 ADC driver - * - * Copyright 2011 Analog Devices Inc. - */ - -#ifndef IIO_ADC_AD7606_H_ -#define IIO_ADC_AD7606_H_ - -/** - * struct ad7606_chip_info - chip specific information - * @channels: channel specification - * @num_channels: number of channels - * @has_oversampling: whether the device has oversampling support - */ -struct ad7606_chip_info { - const struct iio_chan_spec *channels; - unsigned int num_channels; - bool has_oversampling; -}; - -/** - * struct ad7606_state - driver instance specific data - * @dev pointer to kernel device - * @chip_info entry in the table of chips that describes this device - * @reg regulator info for the the power supply of the device - * @bops bus operations (SPI or parallel) - * @range voltage range selection, selects which scale to apply - * @oversampling oversampling selection - * @base_address address from where to read data in parallel operation - * @lock protect sensor state from concurrent accesses to GPIOs - * @gpio_convst GPIO descriptor for conversion start signal (CONVST) - * @gpio_reset GPIO descriptor for device hard-reset - * @gpio_range GPIO descriptor for range selection - * @gpio_standby GPIO descriptor for stand-by signal (STBY), - * controls power-down mode of device - * @gpio_frstdata GPIO descriptor for reading from device when data - * is being read on the first channel - * @gpio_os GPIO descriptors to control oversampling on the device - * @complete completion to indicate end of conversion - * @trig The IIO trigger associated with the device. - * @data buffer for reading data from the device - */ -struct ad7606_state { - struct device *dev; - const struct ad7606_chip_info *chip_info; - struct regulator *reg; - const struct ad7606_bus_ops *bops; - unsigned int range; - unsigned int oversampling; - void __iomem *base_address; - - struct mutex lock; /* protect sensor state */ - struct gpio_desc *gpio_convst; - struct gpio_desc *gpio_reset; - struct gpio_desc *gpio_range; - struct gpio_desc *gpio_standby; - struct gpio_desc *gpio_frstdata; - struct gpio_descs *gpio_os; - struct iio_trigger *trig; - struct completion completion; - - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - * 8 * 16-bit samples + 64-bit timestamp - */ - unsigned short data[12] ____cacheline_aligned; -}; - -/** - * struct ad7606_bus_ops - driver bus operations - * @read_block function pointer for reading blocks of data - */ -struct ad7606_bus_ops { - /* more methods added in future? */ - int (*read_block)(struct device *dev, int num, void *data); -}; - -int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, - const char *name, unsigned int id, - const struct ad7606_bus_ops *bops); - -enum ad7606_supported_device_ids { - ID_AD7605_4, - ID_AD7606_8, - ID_AD7606_6, - ID_AD7606_4 -}; - -#ifdef CONFIG_PM_SLEEP -extern const struct dev_pm_ops ad7606_pm_ops; -#define AD7606_PM_OPS (&ad7606_pm_ops) -#else -#define AD7606_PM_OPS NULL -#endif - -#endif /* IIO_ADC_AD7606_H_ */ diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c deleted file mode 100644 index 1b08028facde..000000000000 --- a/drivers/staging/iio/adc/ad7606_par.c +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * AD7606 Parallel Interface ADC driver - * - * Copyright 2011 Analog Devices Inc. - */ - -#include -#include -#include -#include -#include - -#include -#include "ad7606.h" - -static int ad7606_par16_read_block(struct device *dev, - int count, void *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - insw((unsigned long)st->base_address, buf, count); - - return 0; -} - -static const struct ad7606_bus_ops ad7606_par16_bops = { - .read_block = ad7606_par16_read_block, -}; - -static int ad7606_par8_read_block(struct device *dev, - int count, void *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - insb((unsigned long)st->base_address, buf, count * 2); - - return 0; -} - -static const struct ad7606_bus_ops ad7606_par8_bops = { - .read_block = ad7606_par8_read_block, -}; - -static int ad7606_par_probe(struct platform_device *pdev) -{ - const struct platform_device_id *id = platform_get_device_id(pdev); - struct resource *res; - void __iomem *addr; - resource_size_t remap_size; - int irq; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq: %d\n", irq); - return irq; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(addr)) - return PTR_ERR(addr); - - remap_size = resource_size(res); - - return ad7606_probe(&pdev->dev, irq, addr, - id->name, id->driver_data, - remap_size > 1 ? &ad7606_par16_bops : - &ad7606_par8_bops); -} - -static const struct platform_device_id ad7606_driver_ids[] = { - { .name = "ad7605-4", .driver_data = ID_AD7605_4, }, - { .name = "ad7606-4", .driver_data = ID_AD7606_4, }, - { .name = "ad7606-6", .driver_data = ID_AD7606_6, }, - { .name = "ad7606-8", .driver_data = ID_AD7606_8, }, - { } -}; -MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); - -static const struct of_device_id ad7606_of_match[] = { - { .compatible = "adi,ad7605-4" }, - { .compatible = "adi,ad7606-4" }, - { .compatible = "adi,ad7606-6" }, - { .compatible = "adi,ad7606-8" }, - { }, -}; -MODULE_DEVICE_TABLE(of, ad7606_of_match); - -static struct platform_driver ad7606_driver = { - .probe = ad7606_par_probe, - .id_table = ad7606_driver_ids, - .driver = { - .name = "ad7606", - .pm = AD7606_PM_OPS, - .of_match_table = ad7606_of_match, - }, -}; -module_platform_driver(ad7606_driver); - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c deleted file mode 100644 index 4fd0ec36a086..000000000000 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * AD7606 SPI ADC driver - * - * Copyright 2011 Analog Devices Inc. - */ - -#include -#include -#include -#include - -#include -#include "ad7606.h" - -#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ - -static int ad7606_spi_read_block(struct device *dev, - int count, void *buf) -{ - struct spi_device *spi = to_spi_device(dev); - int i, ret; - unsigned short *data = buf; - __be16 *bdata = buf; - - ret = spi_read(spi, buf, count * 2); - if (ret < 0) { - dev_err(&spi->dev, "SPI read error\n"); - return ret; - } - - for (i = 0; i < count; i++) - data[i] = be16_to_cpu(bdata[i]); - - return 0; -} - -static const struct ad7606_bus_ops ad7606_spi_bops = { - .read_block = ad7606_spi_read_block, -}; - -static int ad7606_spi_probe(struct spi_device *spi) -{ - const struct spi_device_id *id = spi_get_device_id(spi); - - return ad7606_probe(&spi->dev, spi->irq, NULL, - id->name, id->driver_data, - &ad7606_spi_bops); -} - -static const struct spi_device_id ad7606_id_table[] = { - { "ad7605-4", ID_AD7605_4 }, - { "ad7606-4", ID_AD7606_4 }, - { "ad7606-6", ID_AD7606_6 }, - { "ad7606-8", ID_AD7606_8 }, - {} -}; -MODULE_DEVICE_TABLE(spi, ad7606_id_table); - -static const struct of_device_id ad7606_of_match[] = { - { .compatible = "adi,ad7605-4" }, - { .compatible = "adi,ad7606-4" }, - { .compatible = "adi,ad7606-6" }, - { .compatible = "adi,ad7606-8" }, - { }, -}; -MODULE_DEVICE_TABLE(of, ad7606_of_match); - -static struct spi_driver ad7606_driver = { - .driver = { - .name = "ad7606", - .of_match_table = ad7606_of_match, - .pm = AD7606_PM_OPS, - }, - .probe = ad7606_spi_probe, - .id_table = ad7606_id_table, -}; -module_spi_driver(ad7606_driver); - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b002bf5f8dbca8465b1dadb283154e844c61d73f Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Thu, 27 Dec 2018 22:50:20 +0100 Subject: iio: adc: meson-saradc: enable the temperature sensor two more SoCs Meson8b and Meson8m2 use the same logic to convert the ADC register value to celsius, which is different from Meson8: - Meson8 has different multiplier and divider values - Meson8 uses a 4-bit TSC (temperature sensor coefficient) which fits into the 4-bit field in the MESON_SAR_ADC_DELTA_10 register: MESON_SAR_ADC_DELTA_10_TS_C_MASK. Meson8b and Meson8m2 have a 5-bit TSC which requires writing the upper-most bit into the MESON_HHI_DPLL_TOP_0[9] register from the HHI register area. This adds support for the temperature sensor on the Meson8b and Meson8m2 SoCs by implementing the logic to write the upper-most TSC bit into the HHI register area. The SoC-specific values (temperature_trimming_bits, temperature_multiplier, temperature_divider) are added - these simply integrate into the existing infrastructure (which was implemented for Meson8) and thus require no further changes to the existing temperature calculation logic. Signed-off-by: Martin Blumenstingl Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 729becb2d3d9..f8600fbcdfe3 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -26,6 +26,7 @@ #include #include #include +#include #define MESON_SAR_ADC_REG0 0x00 #define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31) @@ -174,6 +175,9 @@ #define MESON_SAR_ADC_EFUSE_BYTE3_UPPER_ADC_VAL GENMASK(6, 0) #define MESON_SAR_ADC_EFUSE_BYTE3_IS_CALIBRATED BIT(7) +#define MESON_HHI_DPLL_TOP_0 0x318 +#define MESON_HHI_DPLL_TOP_0_TSC_BIT4 BIT(9) + /* for use with IIO_VAL_INT_PLUS_MICRO */ #define MILLION 1000000 @@ -280,6 +284,7 @@ struct meson_sar_adc_priv { struct completion done; int calibbias; int calibscale; + struct regmap *tsc_regmap; bool temperature_sensor_calibrated; u8 temperature_sensor_coefficient; u16 temperature_sensor_adc_val; @@ -727,6 +732,15 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev) return ret; } + priv->tsc_regmap = + syscon_regmap_lookup_by_phandle(indio_dev->dev.parent->of_node, + "amlogic,hhi-sysctrl"); + if (IS_ERR(priv->tsc_regmap)) { + dev_err(indio_dev->dev.parent, + "failed to get amlogic,hhi-sysctrl regmap\n"); + return PTR_ERR(priv->tsc_regmap); + } + read_len = MESON_SAR_ADC_EFUSE_BYTES; buf = nvmem_cell_read(temperature_calib, &read_len); if (IS_ERR(buf)) { @@ -861,6 +875,22 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) priv->temperature_sensor_coefficient); regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, MESON_SAR_ADC_DELTA_10_TS_C_MASK, regval); + + if (priv->param->temperature_trimming_bits == 5) { + if (priv->temperature_sensor_coefficient & BIT(4)) + regval = MESON_HHI_DPLL_TOP_0_TSC_BIT4; + else + regval = 0; + + /* + * bit [4] (the 5th bit when starting to count at 1) + * of the TSC is located in the HHI register area. + */ + regmap_update_bits(priv->tsc_regmap, + MESON_HHI_DPLL_TOP_0, + MESON_HHI_DPLL_TOP_0_TSC_BIT4, + regval); + } } else { regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, MESON_SAR_ADC_DELTA_10_TS_REVE1, 0); @@ -1064,6 +1094,9 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = { .bandgap_reg = MESON_SAR_ADC_DELTA_10, .regmap_config = &meson_sar_adc_regmap_config_meson8, .resolution = 10, + .temperature_trimming_bits = 5, + .temperature_multiplier = 10, + .temperature_divider = 32, }; static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = { -- cgit v1.2.3 From 7fc93f3285b17f4632694efce5ff0160303388a8 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Thu, 27 Dec 2018 13:54:52 -0600 Subject: iio: adc: xilinx: check return value of xadc_write_adc_reg In function xadc_probe, xadc_write_adc_reg can return an error value when write fails. The fix checks for the return value consistent with other invocations of the latter function. Signed-off-by: Aditya Pakki Reviewed-by: Michal Simek Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-xadc-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 3f6be5ac049a..b13c61539d46 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1273,8 +1273,10 @@ static int xadc_probe(struct platform_device *pdev) xadc->threshold[i] = 0xffff; else xadc->threshold[i] = 0; - xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i), + ret = xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i), xadc->threshold[i]); + if (ret) + goto err_free_irq; } /* Go to non-buffered mode */ -- cgit v1.2.3 From e9de475723de5bf207a5b7b88bdca863393e42c8 Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Sat, 22 Dec 2018 21:57:40 -0700 Subject: staging: iio: adt7316: fix dac_bits assignment The value of dac_bits is used in adt7316_show_DAC() and adt7316_store_DAC(), and it should be either 8, 10, or 12 bits depending on the device in use. The driver currently only assigns a value to dac_bits in adt7316_store_da_high_resolution(). The purpose of the dac high resolution option is not to change dac resolution for normal operation. Instead, it is specific to an optional feature where one or two of the four dacs can be set to output voltage proportional to temperature. If the user chooses to set dac a and/or dac b to output voltage proportional to temperature, the da_high_resolution attribute can optionally be enabled to use 10 bit resolution rather than the default 8 bits. This is only available on the 10 and 12 bit dac devices. If the user attempts to read or write dacs a or b under these settings, the driver's current behaviour is to return an error. Dacs c and d continue to operate normally under these conditions. With the above in mind, remove the dac_bits assignments from this function since the value of dac_bits as used in the driver is not dependent on this dac high resolution option. Since the dac_bits assignments discussed above are currently the only ones in this driver, the default value of dac_bits is 0. This results in incorrect calculations when the dacs are read or written in adt7316_show_DAC() and adt7316_store_DAC(). To correct this, assign a value to dac_bits in adt7316_probe() to ensure correct operation as soon as the device is registered and available to userspace. Fixes: 35f6b6b86ede ("staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver") Signed-off-by: Jeremy Fertic Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 9db49aa186bb..e17c1cb12c94 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -652,17 +652,10 @@ static ssize_t adt7316_store_da_high_resolution(struct device *dev, u8 config3; int ret; - chip->dac_bits = 8; - - if (buf[0] == '1') { + if (buf[0] == '1') config3 = chip->config3 | ADT7316_DA_HIGH_RESOLUTION; - if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516) - chip->dac_bits = 12; - else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517) - chip->dac_bits = 10; - } else { + else config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION); - } ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3); if (ret) @@ -2145,6 +2138,13 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, else return -ENODEV; + if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516) + chip->dac_bits = 12; + else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517) + chip->dac_bits = 10; + else + chip->dac_bits = 8; + chip->ldac_pin = devm_gpiod_get_optional(dev, "adi,ldac", GPIOD_OUT_LOW); if (IS_ERR(chip->ldac_pin)) { ret = PTR_ERR(chip->ldac_pin); -- cgit v1.2.3 From 76b7fe8d6c4daf4db672eb953c892c6f6572a282 Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Sat, 22 Dec 2018 21:57:41 -0700 Subject: staging: iio: adt7316: fix handling of dac high resolution option The adt7316/7 and adt7516/7 have the option to output voltage proportional to temperature on dac a and/or dac b. The default dac resolution in this mode is 8 bits with the dac high resolution option enabling 10 bits. None of these settings affect dacs c and d. Remove the "1 (12 bits)" output from the show function since that is not an option for this mode. Return "1 (10 bits)" if the device is one of the above mentioned chips and the dac high resolution mode is enabled. In the store function, the driver currently allows the user to write to the ADT7316_DA_HIGH_RESOLUTION bit regardless of the device in use. Add a check to return an error in the case of an adt7318 or adt7519. Remove the else statement that clears the ADT7316_DA_HIGH_RESOLUTION bit. Instead, clear it before conditionally enabling it, depending on user input. This matches the typical pattern in the driver when an attribute is a boolean. Fixes: 35f6b6b86ede ("staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver") Signed-off-by: Jeremy Fertic Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index e17c1cb12c94..80cc3420036b 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -633,9 +633,7 @@ static ssize_t adt7316_show_da_high_resolution(struct device *dev, struct adt7316_chip_info *chip = iio_priv(dev_info); if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) { - if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516) - return sprintf(buf, "1 (12 bits)\n"); - if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517) + if (chip->id != ID_ADT7318 && chip->id != ID_ADT7519) return sprintf(buf, "1 (10 bits)\n"); } @@ -652,10 +650,12 @@ static ssize_t adt7316_store_da_high_resolution(struct device *dev, u8 config3; int ret; + if (chip->id == ID_ADT7318 || chip->id == ID_ADT7519) + return -EPERM; + + config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION); if (buf[0] == '1') - config3 = chip->config3 | ADT7316_DA_HIGH_RESOLUTION; - else - config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION); + config3 |= ADT7316_DA_HIGH_RESOLUTION; ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3); if (ret) -- cgit v1.2.3 From 45130fb030aec26ac28b4bb23344901df3ec3b7f Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Sat, 22 Dec 2018 21:57:42 -0700 Subject: staging: iio: adt7316: fix the dac read calculation The calculation of the current dac value is using the wrong bits of the dac lsb register. Create two macros to shift the lsb register value into lsb position, depending on whether the dac is 10 or 12 bit. Initialize data to 0 so, with an 8 bit dac, the msb register value can be bitwise ORed with data. Fixes: 35f6b6b86ede ("staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver") Signed-off-by: Jeremy Fertic Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 80cc3420036b..d7f3d68e525b 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -47,6 +47,8 @@ #define ADT7516_MSB_AIN3 0xA #define ADT7516_MSB_AIN4 0xB #define ADT7316_DA_DATA_BASE 0x10 +#define ADT7316_DA_10_BIT_LSB_SHIFT 6 +#define ADT7316_DA_12_BIT_LSB_SHIFT 4 #define ADT7316_DA_MSB_DATA_REGS 4 #define ADT7316_LSB_DAC_A 0x10 #define ADT7316_MSB_DAC_A 0x11 @@ -1392,7 +1394,7 @@ static IIO_DEVICE_ATTR(ex_analog_temp_offset, 0644, static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip, int channel, char *buf) { - u16 data; + u16 data = 0; u8 msb, lsb, offset; int ret; @@ -1417,7 +1419,11 @@ static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip, if (ret) return -EIO; - data = (msb << offset) + (lsb & ((1 << offset) - 1)); + if (chip->dac_bits == 12) + data = lsb >> ADT7316_DA_12_BIT_LSB_SHIFT; + else if (chip->dac_bits == 10) + data = lsb >> ADT7316_DA_10_BIT_LSB_SHIFT; + data |= msb << offset; return sprintf(buf, "%d\n", data); } -- cgit v1.2.3 From 78accaea117c1ae878774974fab91ac4a0b0e2b0 Mon Sep 17 00:00:00 2001 From: Jeremy Fertic Date: Sat, 22 Dec 2018 21:57:43 -0700 Subject: staging: iio: adt7316: fix the dac write calculation The lsb calculation is not masking the correct bits from the user input. Subtract 1 from (1 << offset) to correctly set up the mask to be applied to user input. The lsb register stores its value starting at the bit 7 position. adt7316_store_DAC() currently assumes the value is at the other end of the register. Shift the lsb value before storing it in a new variable lsb_reg, and write this variable to the lsb register. Fixes: 35f6b6b86ede ("staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver") Signed-off-by: Jeremy Fertic Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index d7f3d68e525b..6f7891b567b9 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -1431,7 +1431,7 @@ static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip, static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, int channel, const char *buf, size_t len) { - u8 msb, lsb, offset; + u8 msb, lsb, lsb_reg, offset; u16 data; int ret; @@ -1449,9 +1449,13 @@ static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, return -EINVAL; if (chip->dac_bits > 8) { - lsb = data & (1 << offset); + lsb = data & ((1 << offset) - 1); + if (chip->dac_bits == 12) + lsb_reg = lsb << ADT7316_DA_12_BIT_LSB_SHIFT; + else + lsb_reg = lsb << ADT7316_DA_10_BIT_LSB_SHIFT; ret = chip->bus.write(chip->bus.client, - ADT7316_DA_DATA_BASE + channel * 2, lsb); + ADT7316_DA_DATA_BASE + channel * 2, lsb_reg); if (ret) return -EIO; } -- cgit v1.2.3 From e7987a0659421c2bfe5bcf3bc689876ba9be5f3f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Dec 2018 09:57:02 +0100 Subject: dmaengine: at_hdmac: drop useless LIST_HEAD Drop LIST_HEAD where the variable it declares is never used. tmp_list has been declared since the introduction of the driver and has never been used. The two declarations of list were introduced with the containing functions but were also not used. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier x; @@ - LIST_HEAD(x); ... when != x // Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller") Fixes: 4facfe7f09f2b ("dmaengine: hdmac: Split device_control") Acked-by: Ludovic Desroches Signed-off-by: Julia Lawall Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 01d936c9fe89..a0a9cd76c1d4 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -134,7 +134,6 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) struct at_desc *ret = NULL; unsigned long flags; unsigned int i = 0; - LIST_HEAD(tmp_list); spin_lock_irqsave(&atchan->lock, flags); list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) { @@ -1387,8 +1386,6 @@ static int atc_pause(struct dma_chan *chan) int chan_id = atchan->chan_common.chan_id; unsigned long flags; - LIST_HEAD(list); - dev_vdbg(chan2dev(chan), "%s\n", __func__); spin_lock_irqsave(&atchan->lock, flags); @@ -1408,8 +1405,6 @@ static int atc_resume(struct dma_chan *chan) int chan_id = atchan->chan_common.chan_id; unsigned long flags; - LIST_HEAD(list); - dev_vdbg(chan2dev(chan), "%s\n", __func__); if (!atc_chan_is_paused(atchan)) -- cgit v1.2.3 From 1bd09f869f9b294b5645e2ac153ee59604ef959e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Dec 2018 09:57:07 +0100 Subject: dmaengine: dw: drop useless LIST_HEAD Drop LIST_HEAD where the variable it declares is never used. Commit ab703f818ac3 ("dmaengine: dw: lazy allocation of dma descriptors") removed the uses, but not the declaration. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier x; @@ - LIST_HEAD(x); ... when != x // Fixes: ab703f818ac3 ("dmaengine: dw: lazy allocation of dma descriptors") Signed-off-by: Julia Lawall Signed-off-by: Vinod Koul --- drivers/dma/dw/core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index dc053e62f894..290d21be4d4c 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1150,7 +1150,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan) struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_dma *dw = to_dw_dma(chan->device); unsigned long flags; - LIST_HEAD(list); dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__, dwc->descs_allocated); -- cgit v1.2.3 From 3c763b388897a7398ef797b93cbf6580b6ae49e1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Dec 2018 09:57:09 +0100 Subject: dmaengine: st_fdma: drop useless LIST_HEAD Drop LIST_HEAD where the variable it declares is never used. The declarations were introduced with the file, but the declared variables were not used. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier x; @@ - LIST_HEAD(x); ... when != x // Fixes: 6b4cd727eaf1 ("dmaengine: st_fdma: Add STMicroelectronics FDMA engine driver support") Signed-off-by: Julia Lawall Signed-off-by: Vinod Koul --- drivers/dma/st_fdma.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c index 07c20aa2e955..954f7cf62bb1 100644 --- a/drivers/dma/st_fdma.c +++ b/drivers/dma/st_fdma.c @@ -294,8 +294,6 @@ static void st_fdma_free_chan_res(struct dma_chan *chan) struct rproc *rproc = fchan->fdev->slim_rproc->rproc; unsigned long flags; - LIST_HEAD(head); - dev_dbg(fchan->fdev->dev, "%s: freeing chan:%d\n", __func__, fchan->vchan.chan.chan_id); @@ -626,7 +624,6 @@ static void st_fdma_issue_pending(struct dma_chan *chan) static int st_fdma_pause(struct dma_chan *chan) { unsigned long flags; - LIST_HEAD(head); struct st_fdma_chan *fchan = to_st_fdma_chan(chan); int ch_id = fchan->vchan.chan.chan_id; unsigned long cmd = FDMA_CMD_PAUSE(ch_id); -- cgit v1.2.3 From 4f194969c3b01ab080d38114feb09be05b16d7c3 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Dec 2018 09:57:12 +0100 Subject: dmaengine: pl330: drop useless LIST_HEAD Drop LIST_HEAD where the variable it declares is never used. The variable has not been used since the function was introduced in 740aa95703c5 ("dmaengine: pl330: Split device_control"). The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier x; @@ - LIST_HEAD(x); ... when != x // Fixes: 740aa95703c5 ("dmaengine: pl330: Split device_control") Signed-off-by: Julia Lawall Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index cff1b143fff5..eec79fdf27a5 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2267,7 +2267,6 @@ static int pl330_terminate_all(struct dma_chan *chan) struct dma_pl330_desc *desc; unsigned long flags; struct pl330_dmac *pl330 = pch->dmac; - LIST_HEAD(list); bool power_down = false; pm_runtime_get_sync(pl330->ddma.dev); -- cgit v1.2.3 From de2c45314d9bb8839f226dcf989b2582591921f5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Dec 2018 09:57:13 +0100 Subject: dmaengine: sa11x0: drop useless LIST_HEAD Drop LIST_HEAD where the variable it declares has never been used. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier x; @@ - LIST_HEAD(x); ... when != x // Fixes: 4a533218fccf ("dmaengine: sa11x0: Split device_control") Signed-off-by: Julia Lawall Signed-off-by: Vinod Koul --- drivers/dma/sa11x0-dma.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index 784d5f1a473b..3fae23768b47 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -705,7 +705,6 @@ static int sa11x0_dma_device_pause(struct dma_chan *chan) struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); struct sa11x0_dma_phy *p; - LIST_HEAD(head); unsigned long flags; dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc); @@ -732,7 +731,6 @@ static int sa11x0_dma_device_resume(struct dma_chan *chan) struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); struct sa11x0_dma_phy *p; - LIST_HEAD(head); unsigned long flags; dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc); -- cgit v1.2.3 From a7359e762fdd6eea432fefd9d38851540192e7e3 Mon Sep 17 00:00:00 2001 From: Wen He Date: Tue, 30 Oct 2018 10:35:58 +0800 Subject: dmaengine: fsldma: Replace DMA_IN/OUT by FSL_DMA_IN/OUT This patch implement a standard macro call functions is used to NXP dma drivers. Signed-off-by: Wen He Signed-off-by: Peng Ma Signed-off-by: Vinod Koul --- drivers/dma/fsldma.c | 16 ++++++++-------- drivers/dma/fsldma.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 9d360a3fbae3..1e38e6b94006 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -53,42 +53,42 @@ static const char msg_ld_oom[] = "No free memory for link descriptor"; static void set_sr(struct fsldma_chan *chan, u32 val) { - DMA_OUT(chan, &chan->regs->sr, val, 32); + FSL_DMA_OUT(chan, &chan->regs->sr, val, 32); } static u32 get_sr(struct fsldma_chan *chan) { - return DMA_IN(chan, &chan->regs->sr, 32); + return FSL_DMA_IN(chan, &chan->regs->sr, 32); } static void set_mr(struct fsldma_chan *chan, u32 val) { - DMA_OUT(chan, &chan->regs->mr, val, 32); + FSL_DMA_OUT(chan, &chan->regs->mr, val, 32); } static u32 get_mr(struct fsldma_chan *chan) { - return DMA_IN(chan, &chan->regs->mr, 32); + return FSL_DMA_IN(chan, &chan->regs->mr, 32); } static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr) { - DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64); + FSL_DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64); } static dma_addr_t get_cdar(struct fsldma_chan *chan) { - return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; + return FSL_DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; } static void set_bcr(struct fsldma_chan *chan, u32 val) { - DMA_OUT(chan, &chan->regs->bcr, val, 32); + FSL_DMA_OUT(chan, &chan->regs->bcr, val, 32); } static u32 get_bcr(struct fsldma_chan *chan) { - return DMA_IN(chan, &chan->regs->bcr, 32); + return FSL_DMA_IN(chan, &chan->regs->bcr, 32); } /* diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index 4787d485dd76..982845b830c7 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -223,10 +223,10 @@ static void out_le64(u64 __iomem *addr, u64 val) } #endif -#define DMA_IN(fsl_chan, addr, width) \ +#define FSL_DMA_IN(fsl_chan, addr, width) \ (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ in_be##width(addr) : in_le##width(addr)) -#define DMA_OUT(fsl_chan, addr, val, width) \ +#define FSL_DMA_OUT(fsl_chan, addr, val, width) \ (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ out_be##width(addr, val) : out_le##width(addr, val)) -- cgit v1.2.3 From a1ff82a9c165ba26f0e2f4771d0490c513056428 Mon Sep 17 00:00:00 2001 From: Peng Ma Date: Tue, 30 Oct 2018 10:35:59 +0800 Subject: dmaengine: fsldma: Adding macro FSL_DMA_IN/OUT implement for ARM platform This patch add the macro FSL_DMA_IN/OUT implement for ARM platform. Signed-off-by: Wen He Signed-off-by: Peng Ma Signed-off-by: Vinod Koul --- drivers/dma/fsldma.h | 61 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index 982845b830c7..88db939c04a1 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -196,39 +196,62 @@ struct fsldma_chan { #define to_fsl_desc(lh) container_of(lh, struct fsl_desc_sw, node) #define tx_to_fsl_desc(tx) container_of(tx, struct fsl_desc_sw, async_tx) +#ifdef CONFIG_PPC +#define fsl_ioread32(p) in_le32(p) +#define fsl_ioread32be(p) in_be32(p) +#define fsl_iowrite32(v, p) out_le32(p, v) +#define fsl_iowrite32be(v, p) out_be32(p, v) + #ifndef __powerpc64__ -static u64 in_be64(const u64 __iomem *addr) +static u64 fsl_ioread64(const u64 __iomem *addr) { - return ((u64)in_be32((u32 __iomem *)addr) << 32) | - (in_be32((u32 __iomem *)addr + 1)); + u32 fsl_addr = lower_32_bits(addr); + u64 fsl_addr_hi = (u64)in_le32((u32 *)(fsl_addr + 1)) << 32; + + return fsl_addr_hi | in_le32((u32 *)fsl_addr); } -static void out_be64(u64 __iomem *addr, u64 val) +static void fsl_iowrite64(u64 val, u64 __iomem *addr) { - out_be32((u32 __iomem *)addr, val >> 32); - out_be32((u32 __iomem *)addr + 1, (u32)val); + out_le32((u32 __iomem *)addr + 1, val >> 32); + out_le32((u32 __iomem *)addr, (u32)val); } -/* There is no asm instructions for 64 bits reverse loads and stores */ -static u64 in_le64(const u64 __iomem *addr) +static u64 fsl_ioread64be(const u64 __iomem *addr) { - return ((u64)in_le32((u32 __iomem *)addr + 1) << 32) | - (in_le32((u32 __iomem *)addr)); + u32 fsl_addr = lower_32_bits(addr); + u64 fsl_addr_hi = (u64)in_be32((u32 *)fsl_addr) << 32; + + return fsl_addr_hi | in_be32((u32 *)(fsl_addr + 1)); } -static void out_le64(u64 __iomem *addr, u64 val) +static void fsl_iowrite64be(u64 val, u64 __iomem *addr) { - out_le32((u32 __iomem *)addr + 1, val >> 32); - out_le32((u32 __iomem *)addr, (u32)val); + out_be32((u32 __iomem *)addr, val >> 32); + out_be32((u32 __iomem *)addr + 1, (u32)val); } #endif +#endif -#define FSL_DMA_IN(fsl_chan, addr, width) \ - (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ - in_be##width(addr) : in_le##width(addr)) -#define FSL_DMA_OUT(fsl_chan, addr, val, width) \ - (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ - out_be##width(addr, val) : out_le##width(addr, val)) +#if defined(CONFIG_ARM64) || defined(CONFIG_ARM) +#define fsl_ioread32(p) ioread32(p) +#define fsl_ioread32be(p) ioread32be(p) +#define fsl_iowrite32(v, p) iowrite32(v, p) +#define fsl_iowrite32be(v, p) iowrite32be(v, p) +#define fsl_ioread64(p) ioread64(p) +#define fsl_ioread64be(p) ioread64be(p) +#define fsl_iowrite64(v, p) iowrite64(v, p) +#define fsl_iowrite64be(v, p) iowrite64be(v, p) +#endif + +#define FSL_DMA_IN(fsl_dma, addr, width) \ + (((fsl_dma)->feature & FSL_DMA_BIG_ENDIAN) ? \ + fsl_ioread##width##be(addr) : fsl_ioread##width(addr)) + +#define FSL_DMA_OUT(fsl_dma, addr, val, width) \ + (((fsl_dma)->feature & FSL_DMA_BIG_ENDIAN) ? \ + fsl_iowrite##width##be(val, addr) : fsl_iowrite \ + ##width(val, addr)) #define DMA_TO_CPU(fsl_chan, d, width) \ (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ -- cgit v1.2.3 From b092529e0aa09829a6404424ce167bf3ce3235e2 Mon Sep 17 00:00:00 2001 From: Peng Ma Date: Tue, 30 Oct 2018 10:36:00 +0800 Subject: dmaengine: fsl-qdma: Add qDMA controller driver for Layerscape SoCs NXP Queue DMA controller(qDMA) on Layerscape SoCs supports channel virtuallization by allowing DMA jobs to be enqueued into different command queues. Signed-off-by: Wen He Signed-off-by: Jiaheng Fan Signed-off-by: Peng Ma Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 14 + drivers/dma/Makefile | 1 + drivers/dma/fsl-qdma.c | 1258 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1273 insertions(+) create mode 100644 drivers/dma/fsl-qdma.c (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d2286c7f7222..0b1dfb5bf2d9 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -218,6 +218,20 @@ config FSL_EDMA multiplexing capability for DMA request sources(slot). This module can be found on Freescale Vybrid and LS-1 SoCs. +config FSL_QDMA + tristate "NXP Layerscape qDMA engine support" + depends on ARM || ARM64 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + select DMA_ENGINE_RAID + select ASYNC_TX_ENABLE_CHANNEL_SWITCH + help + Support the NXP Layerscape qDMA engine with command queue and legacy mode. + Channel virtualization is supported through enqueuing of DMA jobs to, + or dequeuing DMA jobs from, different work queues. + This module can be found on NXP Layerscape SoCs. + The qdma driver only work on SoCs with a DPAA hardware block. + config FSL_RAID tristate "Freescale RAID engine Support" depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 09571a81353d..6126e1c3a875 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_FSL_DMA) += fsldma.o obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o +obj-$(CONFIG_FSL_QDMA) += fsl-qdma.o obj-$(CONFIG_FSL_RAID) += fsl_raid.o obj-$(CONFIG_HSU_DMA) += hsu/ obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c new file mode 100644 index 000000000000..c18e3492090b --- /dev/null +++ b/drivers/dma/fsl-qdma.c @@ -0,0 +1,1258 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2014-2015 Freescale +// Copyright 2018 NXP + +/* + * Driver for NXP Layerscape Queue Direct Memory Access Controller + * + * Author: + * Wen He + * Jiaheng Fan + * + */ + +#include +#include +#include +#include +#include +#include + +#include "virt-dma.h" +#include "fsldma.h" + +/* Register related definition */ +#define FSL_QDMA_DMR 0x0 +#define FSL_QDMA_DSR 0x4 +#define FSL_QDMA_DEIER 0xe00 +#define FSL_QDMA_DEDR 0xe04 +#define FSL_QDMA_DECFDW0R 0xe10 +#define FSL_QDMA_DECFDW1R 0xe14 +#define FSL_QDMA_DECFDW2R 0xe18 +#define FSL_QDMA_DECFDW3R 0xe1c +#define FSL_QDMA_DECFQIDR 0xe30 +#define FSL_QDMA_DECBR 0xe34 + +#define FSL_QDMA_BCQMR(x) (0xc0 + 0x100 * (x)) +#define FSL_QDMA_BCQSR(x) (0xc4 + 0x100 * (x)) +#define FSL_QDMA_BCQEDPA_SADDR(x) (0xc8 + 0x100 * (x)) +#define FSL_QDMA_BCQDPA_SADDR(x) (0xcc + 0x100 * (x)) +#define FSL_QDMA_BCQEEPA_SADDR(x) (0xd0 + 0x100 * (x)) +#define FSL_QDMA_BCQEPA_SADDR(x) (0xd4 + 0x100 * (x)) +#define FSL_QDMA_BCQIER(x) (0xe0 + 0x100 * (x)) +#define FSL_QDMA_BCQIDR(x) (0xe4 + 0x100 * (x)) + +#define FSL_QDMA_SQDPAR 0x80c +#define FSL_QDMA_SQEPAR 0x814 +#define FSL_QDMA_BSQMR 0x800 +#define FSL_QDMA_BSQSR 0x804 +#define FSL_QDMA_BSQICR 0x828 +#define FSL_QDMA_CQMR 0xa00 +#define FSL_QDMA_CQDSCR1 0xa08 +#define FSL_QDMA_CQDSCR2 0xa0c +#define FSL_QDMA_CQIER 0xa10 +#define FSL_QDMA_CQEDR 0xa14 +#define FSL_QDMA_SQCCMR 0xa20 + +/* Registers for bit and genmask */ +#define FSL_QDMA_CQIDR_SQT BIT(15) +#define QDMA_CCDF_FOTMAT BIT(29) +#define QDMA_CCDF_SER BIT(30) +#define QDMA_SG_FIN BIT(30) +#define QDMA_SG_LEN_MASK GENMASK(29, 0) +#define QDMA_CCDF_MASK GENMASK(28, 20) + +#define FSL_QDMA_DEDR_CLEAR GENMASK(31, 0) +#define FSL_QDMA_BCQIDR_CLEAR GENMASK(31, 0) +#define FSL_QDMA_DEIER_CLEAR GENMASK(31, 0) + +#define FSL_QDMA_BCQIER_CQTIE BIT(15) +#define FSL_QDMA_BCQIER_CQPEIE BIT(23) +#define FSL_QDMA_BSQICR_ICEN BIT(31) + +#define FSL_QDMA_BSQICR_ICST(x) ((x) << 16) +#define FSL_QDMA_CQIER_MEIE BIT(31) +#define FSL_QDMA_CQIER_TEIE BIT(0) +#define FSL_QDMA_SQCCMR_ENTER_WM BIT(21) + +#define FSL_QDMA_BCQMR_EN BIT(31) +#define FSL_QDMA_BCQMR_EI BIT(30) +#define FSL_QDMA_BCQMR_CD_THLD(x) ((x) << 20) +#define FSL_QDMA_BCQMR_CQ_SIZE(x) ((x) << 16) + +#define FSL_QDMA_BCQSR_QF BIT(16) +#define FSL_QDMA_BCQSR_XOFF BIT(0) + +#define FSL_QDMA_BSQMR_EN BIT(31) +#define FSL_QDMA_BSQMR_DI BIT(30) +#define FSL_QDMA_BSQMR_CQ_SIZE(x) ((x) << 16) + +#define FSL_QDMA_BSQSR_QE BIT(17) + +#define FSL_QDMA_DMR_DQD BIT(30) +#define FSL_QDMA_DSR_DB BIT(31) + +/* Size related definition */ +#define FSL_QDMA_QUEUE_MAX 8 +#define FSL_QDMA_COMMAND_BUFFER_SIZE 64 +#define FSL_QDMA_DESCRIPTOR_BUFFER_SIZE 32 +#define FSL_QDMA_CIRCULAR_DESC_SIZE_MIN 64 +#define FSL_QDMA_CIRCULAR_DESC_SIZE_MAX 16384 +#define FSL_QDMA_QUEUE_NUM_MAX 8 + +/* Field definition for CMD */ +#define FSL_QDMA_CMD_RWTTYPE 0x4 +#define FSL_QDMA_CMD_LWC 0x2 +#define FSL_QDMA_CMD_RWTTYPE_OFFSET 28 +#define FSL_QDMA_CMD_NS_OFFSET 27 +#define FSL_QDMA_CMD_DQOS_OFFSET 24 +#define FSL_QDMA_CMD_WTHROTL_OFFSET 20 +#define FSL_QDMA_CMD_DSEN_OFFSET 19 +#define FSL_QDMA_CMD_LWC_OFFSET 16 + +/* Field definition for Descriptor offset */ +#define QDMA_CCDF_STATUS 20 +#define QDMA_CCDF_OFFSET 20 + +/* Field definition for safe loop count*/ +#define FSL_QDMA_HALT_COUNT 1500 +#define FSL_QDMA_MAX_SIZE 16385 +#define FSL_QDMA_COMP_TIMEOUT 1000 +#define FSL_COMMAND_QUEUE_OVERFLLOW 10 + +#define FSL_QDMA_BLOCK_BASE_OFFSET(fsl_qdma_engine, x) \ + (((fsl_qdma_engine)->block_offset) * (x)) + +/** + * struct fsl_qdma_format - This is the struct holding describing compound + * descriptor format with qDMA. + * @status: Command status and enqueue status notification. + * @cfg: Frame offset and frame format. + * @addr_lo: Holding the compound descriptor of the lower + * 32-bits address in memory 40-bit address. + * @addr_hi: Same as above member, but point high 8-bits in + * memory 40-bit address. + * @__reserved1: Reserved field. + * @cfg8b_w1: Compound descriptor command queue origin produced + * by qDMA and dynamic debug field. + * @data Pointer to the memory 40-bit address, describes DMA + * source information and DMA destination information. + */ +struct fsl_qdma_format { + __le32 status; + __le32 cfg; + union { + struct { + __le32 addr_lo; + u8 addr_hi; + u8 __reserved1[2]; + u8 cfg8b_w1; + } __packed; + __le64 data; + }; +} __packed; + +/* qDMA status notification pre information */ +struct fsl_pre_status { + u64 addr; + u8 queue; +}; + +static DEFINE_PER_CPU(struct fsl_pre_status, pre); + +struct fsl_qdma_chan { + struct virt_dma_chan vchan; + struct virt_dma_desc vdesc; + enum dma_status status; + struct fsl_qdma_engine *qdma; + struct fsl_qdma_queue *queue; +}; + +struct fsl_qdma_queue { + struct fsl_qdma_format *virt_head; + struct fsl_qdma_format *virt_tail; + struct list_head comp_used; + struct list_head comp_free; + struct dma_pool *comp_pool; + struct dma_pool *desc_pool; + spinlock_t queue_lock; + dma_addr_t bus_addr; + u32 n_cq; + u32 id; + struct fsl_qdma_format *cq; + void __iomem *block_base; +}; + +struct fsl_qdma_comp { + dma_addr_t bus_addr; + dma_addr_t desc_bus_addr; + struct fsl_qdma_format *virt_addr; + struct fsl_qdma_format *desc_virt_addr; + struct fsl_qdma_chan *qchan; + struct virt_dma_desc vdesc; + struct list_head list; +}; + +struct fsl_qdma_engine { + struct dma_device dma_dev; + void __iomem *ctrl_base; + void __iomem *status_base; + void __iomem *block_base; + u32 n_chans; + u32 n_queues; + struct mutex fsl_qdma_mutex; + int error_irq; + int *queue_irq; + u32 feature; + struct fsl_qdma_queue *queue; + struct fsl_qdma_queue **status; + struct fsl_qdma_chan *chans; + int block_number; + int block_offset; + int irq_base; + int desc_allocated; + +}; + +static inline u64 +qdma_ccdf_addr_get64(const struct fsl_qdma_format *ccdf) +{ + return le64_to_cpu(ccdf->data) & (U64_MAX >> 24); +} + +static inline void +qdma_desc_addr_set64(struct fsl_qdma_format *ccdf, u64 addr) +{ + ccdf->addr_hi = upper_32_bits(addr); + ccdf->addr_lo = cpu_to_le32(lower_32_bits(addr)); +} + +static inline u8 +qdma_ccdf_get_queue(const struct fsl_qdma_format *ccdf) +{ + return ccdf->cfg8b_w1 & U8_MAX; +} + +static inline int +qdma_ccdf_get_offset(const struct fsl_qdma_format *ccdf) +{ + return (le32_to_cpu(ccdf->cfg) & QDMA_CCDF_MASK) >> QDMA_CCDF_OFFSET; +} + +static inline void +qdma_ccdf_set_format(struct fsl_qdma_format *ccdf, int offset) +{ + ccdf->cfg = cpu_to_le32(QDMA_CCDF_FOTMAT | offset); +} + +static inline int +qdma_ccdf_get_status(const struct fsl_qdma_format *ccdf) +{ + return (le32_to_cpu(ccdf->status) & QDMA_CCDF_MASK) >> QDMA_CCDF_STATUS; +} + +static inline void +qdma_ccdf_set_ser(struct fsl_qdma_format *ccdf, int status) +{ + ccdf->status = cpu_to_le32(QDMA_CCDF_SER | status); +} + +static inline void qdma_csgf_set_len(struct fsl_qdma_format *csgf, int len) +{ + csgf->cfg = cpu_to_le32(len & QDMA_SG_LEN_MASK); +} + +static inline void qdma_csgf_set_f(struct fsl_qdma_format *csgf, int len) +{ + csgf->cfg = cpu_to_le32(QDMA_SG_FIN | (len & QDMA_SG_LEN_MASK)); +} + +static u32 qdma_readl(struct fsl_qdma_engine *qdma, void __iomem *addr) +{ + return FSL_DMA_IN(qdma, addr, 32); +} + +static void qdma_writel(struct fsl_qdma_engine *qdma, u32 val, + void __iomem *addr) +{ + FSL_DMA_OUT(qdma, addr, val, 32); +} + +static struct fsl_qdma_chan *to_fsl_qdma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct fsl_qdma_chan, vchan.chan); +} + +static struct fsl_qdma_comp *to_fsl_qdma_comp(struct virt_dma_desc *vd) +{ + return container_of(vd, struct fsl_qdma_comp, vdesc); +} + +static void fsl_qdma_free_chan_resources(struct dma_chan *chan) +{ + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue; + struct fsl_qdma_engine *fsl_qdma = fsl_chan->qdma; + struct fsl_qdma_comp *comp_temp, *_comp_temp; + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + vchan_get_all_descriptors(&fsl_chan->vchan, &head); + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + + vchan_dma_desc_free_list(&fsl_chan->vchan, &head); + + if (!fsl_queue->comp_pool && !fsl_queue->comp_pool) + return; + + list_for_each_entry_safe(comp_temp, _comp_temp, + &fsl_queue->comp_used, list) { + dma_pool_free(fsl_queue->comp_pool, + comp_temp->virt_addr, + comp_temp->bus_addr); + dma_pool_free(fsl_queue->desc_pool, + comp_temp->desc_virt_addr, + comp_temp->desc_bus_addr); + list_del(&comp_temp->list); + kfree(comp_temp); + } + + list_for_each_entry_safe(comp_temp, _comp_temp, + &fsl_queue->comp_free, list) { + dma_pool_free(fsl_queue->comp_pool, + comp_temp->virt_addr, + comp_temp->bus_addr); + dma_pool_free(fsl_queue->desc_pool, + comp_temp->desc_virt_addr, + comp_temp->desc_bus_addr); + list_del(&comp_temp->list); + kfree(comp_temp); + } + + dma_pool_destroy(fsl_queue->comp_pool); + dma_pool_destroy(fsl_queue->desc_pool); + + fsl_qdma->desc_allocated--; + fsl_queue->comp_pool = NULL; + fsl_queue->desc_pool = NULL; +} + +static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp, + dma_addr_t dst, dma_addr_t src, u32 len) +{ + struct fsl_qdma_format *sdf, *ddf; + struct fsl_qdma_format *ccdf, *csgf_desc, *csgf_src, *csgf_dest; + + ccdf = fsl_comp->virt_addr; + csgf_desc = fsl_comp->virt_addr + 1; + csgf_src = fsl_comp->virt_addr + 2; + csgf_dest = fsl_comp->virt_addr + 3; + sdf = fsl_comp->desc_virt_addr; + ddf = fsl_comp->desc_virt_addr + 1; + + memset(fsl_comp->virt_addr, 0, FSL_QDMA_COMMAND_BUFFER_SIZE); + memset(fsl_comp->desc_virt_addr, 0, FSL_QDMA_DESCRIPTOR_BUFFER_SIZE); + /* Head Command Descriptor(Frame Descriptor) */ + qdma_desc_addr_set64(ccdf, fsl_comp->bus_addr + 16); + qdma_ccdf_set_format(ccdf, qdma_ccdf_get_offset(ccdf)); + qdma_ccdf_set_ser(ccdf, qdma_ccdf_get_status(ccdf)); + /* Status notification is enqueued to status queue. */ + /* Compound Command Descriptor(Frame List Table) */ + qdma_desc_addr_set64(csgf_desc, fsl_comp->desc_bus_addr); + /* It must be 32 as Compound S/G Descriptor */ + qdma_csgf_set_len(csgf_desc, 32); + qdma_desc_addr_set64(csgf_src, src); + qdma_csgf_set_len(csgf_src, len); + qdma_desc_addr_set64(csgf_dest, dst); + qdma_csgf_set_len(csgf_dest, len); + /* This entry is the last entry. */ + qdma_csgf_set_f(csgf_dest, len); + /* Descriptor Buffer */ + sdf->data = + cpu_to_le64(FSL_QDMA_CMD_RWTTYPE << + FSL_QDMA_CMD_RWTTYPE_OFFSET); + ddf->data = + cpu_to_le64(FSL_QDMA_CMD_RWTTYPE << + FSL_QDMA_CMD_RWTTYPE_OFFSET); + ddf->data |= + cpu_to_le64(FSL_QDMA_CMD_LWC << FSL_QDMA_CMD_LWC_OFFSET); +} + +/* + * Pre-request full command descriptor for enqueue. + */ +static int fsl_qdma_pre_request_enqueue_desc(struct fsl_qdma_queue *queue) +{ + int i; + struct fsl_qdma_comp *comp_temp, *_comp_temp; + + for (i = 0; i < queue->n_cq + FSL_COMMAND_QUEUE_OVERFLLOW; i++) { + comp_temp = kzalloc(sizeof(*comp_temp), GFP_KERNEL); + if (!comp_temp) + goto err_alloc; + comp_temp->virt_addr = + dma_pool_alloc(queue->comp_pool, GFP_KERNEL, + &comp_temp->bus_addr); + if (!comp_temp->virt_addr) + goto err_dma_alloc; + + comp_temp->desc_virt_addr = + dma_pool_alloc(queue->desc_pool, GFP_KERNEL, + &comp_temp->desc_bus_addr); + if (!comp_temp->desc_virt_addr) + goto err_desc_dma_alloc; + + list_add_tail(&comp_temp->list, &queue->comp_free); + } + + return 0; + +err_desc_dma_alloc: + dma_pool_free(queue->comp_pool, comp_temp->virt_addr, + comp_temp->bus_addr); + +err_dma_alloc: + kfree(comp_temp); + +err_alloc: + list_for_each_entry_safe(comp_temp, _comp_temp, + &queue->comp_free, list) { + if (comp_temp->virt_addr) + dma_pool_free(queue->comp_pool, + comp_temp->virt_addr, + comp_temp->bus_addr); + if (comp_temp->desc_virt_addr) + dma_pool_free(queue->desc_pool, + comp_temp->desc_virt_addr, + comp_temp->desc_bus_addr); + + list_del(&comp_temp->list); + kfree(comp_temp); + } + + return -ENOMEM; +} + +/* + * Request a command descriptor for enqueue. + */ +static struct fsl_qdma_comp +*fsl_qdma_request_enqueue_desc(struct fsl_qdma_chan *fsl_chan) +{ + unsigned long flags; + struct fsl_qdma_comp *comp_temp; + int timeout = FSL_QDMA_COMP_TIMEOUT; + struct fsl_qdma_queue *queue = fsl_chan->queue; + + while (timeout--) { + spin_lock_irqsave(&queue->queue_lock, flags); + if (!list_empty(&queue->comp_free)) { + comp_temp = list_first_entry(&queue->comp_free, + struct fsl_qdma_comp, + list); + list_del(&comp_temp->list); + + spin_unlock_irqrestore(&queue->queue_lock, flags); + comp_temp->qchan = fsl_chan; + return comp_temp; + } + spin_unlock_irqrestore(&queue->queue_lock, flags); + udelay(1); + } + + return NULL; +} + +static struct fsl_qdma_queue +*fsl_qdma_alloc_queue_resources(struct platform_device *pdev, + struct fsl_qdma_engine *fsl_qdma) +{ + int ret, len, i, j; + int queue_num, block_number; + unsigned int queue_size[FSL_QDMA_QUEUE_MAX]; + struct fsl_qdma_queue *queue_head, *queue_temp; + + queue_num = fsl_qdma->n_queues; + block_number = fsl_qdma->block_number; + + if (queue_num > FSL_QDMA_QUEUE_MAX) + queue_num = FSL_QDMA_QUEUE_MAX; + len = sizeof(*queue_head) * queue_num * block_number; + queue_head = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!queue_head) + return NULL; + + ret = device_property_read_u32_array(&pdev->dev, "queue-sizes", + queue_size, queue_num); + if (ret) { + dev_err(&pdev->dev, "Can't get queue-sizes.\n"); + return NULL; + } + for (j = 0; j < block_number; j++) { + for (i = 0; i < queue_num; i++) { + if (queue_size[i] > FSL_QDMA_CIRCULAR_DESC_SIZE_MAX || + queue_size[i] < FSL_QDMA_CIRCULAR_DESC_SIZE_MIN) { + dev_err(&pdev->dev, + "Get wrong queue-sizes.\n"); + return NULL; + } + queue_temp = queue_head + i + (j * queue_num); + + queue_temp->cq = + dma_alloc_coherent(&pdev->dev, + sizeof(struct fsl_qdma_format) * + queue_size[i], + &queue_temp->bus_addr, + GFP_KERNEL); + if (!queue_temp->cq) + return NULL; + queue_temp->block_base = fsl_qdma->block_base + + FSL_QDMA_BLOCK_BASE_OFFSET(fsl_qdma, j); + queue_temp->n_cq = queue_size[i]; + queue_temp->id = i; + queue_temp->virt_head = queue_temp->cq; + queue_temp->virt_tail = queue_temp->cq; + /* + * List for queue command buffer + */ + INIT_LIST_HEAD(&queue_temp->comp_used); + spin_lock_init(&queue_temp->queue_lock); + } + } + return queue_head; +} + +static struct fsl_qdma_queue +*fsl_qdma_prep_status_queue(struct platform_device *pdev) +{ + int ret; + unsigned int status_size; + struct fsl_qdma_queue *status_head; + struct device_node *np = pdev->dev.of_node; + + ret = of_property_read_u32(np, "status-sizes", &status_size); + if (ret) { + dev_err(&pdev->dev, "Can't get status-sizes.\n"); + return NULL; + } + if (status_size > FSL_QDMA_CIRCULAR_DESC_SIZE_MAX || + status_size < FSL_QDMA_CIRCULAR_DESC_SIZE_MIN) { + dev_err(&pdev->dev, "Get wrong status_size.\n"); + return NULL; + } + status_head = devm_kzalloc(&pdev->dev, + sizeof(*status_head), GFP_KERNEL); + if (!status_head) + return NULL; + + /* + * Buffer for queue command + */ + status_head->cq = dma_alloc_coherent(&pdev->dev, + sizeof(struct fsl_qdma_format) * + status_size, + &status_head->bus_addr, + GFP_KERNEL); + if (!status_head->cq) { + devm_kfree(&pdev->dev, status_head); + return NULL; + } + status_head->n_cq = status_size; + status_head->virt_head = status_head->cq; + status_head->virt_tail = status_head->cq; + status_head->comp_pool = NULL; + + return status_head; +} + +static int fsl_qdma_halt(struct fsl_qdma_engine *fsl_qdma) +{ + u32 reg; + int i, j, count = FSL_QDMA_HALT_COUNT; + void __iomem *block, *ctrl = fsl_qdma->ctrl_base; + + /* Disable the command queue and wait for idle state. */ + reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DMR); + reg |= FSL_QDMA_DMR_DQD; + qdma_writel(fsl_qdma, reg, ctrl + FSL_QDMA_DMR); + for (j = 0; j < fsl_qdma->block_number; j++) { + block = fsl_qdma->block_base + + FSL_QDMA_BLOCK_BASE_OFFSET(fsl_qdma, j); + for (i = 0; i < FSL_QDMA_QUEUE_NUM_MAX; i++) + qdma_writel(fsl_qdma, 0, block + FSL_QDMA_BCQMR(i)); + } + while (1) { + reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DSR); + if (!(reg & FSL_QDMA_DSR_DB)) + break; + if (count-- < 0) + return -EBUSY; + udelay(100); + } + + for (j = 0; j < fsl_qdma->block_number; j++) { + block = fsl_qdma->block_base + + FSL_QDMA_BLOCK_BASE_OFFSET(fsl_qdma, j); + + /* Disable status queue. */ + qdma_writel(fsl_qdma, 0, block + FSL_QDMA_BSQMR); + + /* + * clear the command queue interrupt detect register for + * all queues. + */ + qdma_writel(fsl_qdma, FSL_QDMA_BCQIDR_CLEAR, + block + FSL_QDMA_BCQIDR(0)); + } + + return 0; +} + +static int +fsl_qdma_queue_transfer_complete(struct fsl_qdma_engine *fsl_qdma, + void *block, + int id) +{ + bool duplicate; + u32 reg, i, count; + struct fsl_qdma_queue *temp_queue; + struct fsl_qdma_format *status_addr; + struct fsl_qdma_comp *fsl_comp = NULL; + struct fsl_qdma_queue *fsl_queue = fsl_qdma->queue; + struct fsl_qdma_queue *fsl_status = fsl_qdma->status[id]; + + count = FSL_QDMA_MAX_SIZE; + + while (count--) { + duplicate = 0; + reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQSR); + if (reg & FSL_QDMA_BSQSR_QE) + return 0; + + status_addr = fsl_status->virt_head; + + if (qdma_ccdf_get_queue(status_addr) == + __this_cpu_read(pre.queue) && + qdma_ccdf_addr_get64(status_addr) == + __this_cpu_read(pre.addr)) + duplicate = 1; + i = qdma_ccdf_get_queue(status_addr) + + id * fsl_qdma->n_queues; + __this_cpu_write(pre.addr, qdma_ccdf_addr_get64(status_addr)); + __this_cpu_write(pre.queue, qdma_ccdf_get_queue(status_addr)); + temp_queue = fsl_queue + i; + + spin_lock(&temp_queue->queue_lock); + if (list_empty(&temp_queue->comp_used)) { + if (!duplicate) { + spin_unlock(&temp_queue->queue_lock); + return -EAGAIN; + } + } else { + fsl_comp = list_first_entry(&temp_queue->comp_used, + struct fsl_qdma_comp, list); + if (fsl_comp->bus_addr + 16 != + __this_cpu_read(pre.addr)) { + if (!duplicate) { + spin_unlock(&temp_queue->queue_lock); + return -EAGAIN; + } + } + } + + if (duplicate) { + reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR); + reg |= FSL_QDMA_BSQMR_DI; + qdma_desc_addr_set64(status_addr, 0x0); + fsl_status->virt_head++; + if (fsl_status->virt_head == fsl_status->cq + + fsl_status->n_cq) + fsl_status->virt_head = fsl_status->cq; + qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); + spin_unlock(&temp_queue->queue_lock); + continue; + } + list_del(&fsl_comp->list); + + reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR); + reg |= FSL_QDMA_BSQMR_DI; + qdma_desc_addr_set64(status_addr, 0x0); + fsl_status->virt_head++; + if (fsl_status->virt_head == fsl_status->cq + fsl_status->n_cq) + fsl_status->virt_head = fsl_status->cq; + qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); + spin_unlock(&temp_queue->queue_lock); + + spin_lock(&fsl_comp->qchan->vchan.lock); + vchan_cookie_complete(&fsl_comp->vdesc); + fsl_comp->qchan->status = DMA_COMPLETE; + spin_unlock(&fsl_comp->qchan->vchan.lock); + } + + return 0; +} + +static irqreturn_t fsl_qdma_error_handler(int irq, void *dev_id) +{ + unsigned int intr; + struct fsl_qdma_engine *fsl_qdma = dev_id; + void __iomem *status = fsl_qdma->status_base; + + intr = qdma_readl(fsl_qdma, status + FSL_QDMA_DEDR); + + if (intr) { + dev_err(fsl_qdma->dma_dev.dev, "DMA transaction error!\n"); + return IRQ_NONE; + } + + qdma_writel(fsl_qdma, FSL_QDMA_DEDR_CLEAR, status + FSL_QDMA_DEDR); + return IRQ_HANDLED; +} + +static irqreturn_t fsl_qdma_queue_handler(int irq, void *dev_id) +{ + int id; + unsigned int intr, reg; + struct fsl_qdma_engine *fsl_qdma = dev_id; + void __iomem *block, *ctrl = fsl_qdma->ctrl_base; + + id = irq - fsl_qdma->irq_base; + if (id < 0 && id > fsl_qdma->block_number) { + dev_err(fsl_qdma->dma_dev.dev, + "irq %d is wrong irq_base is %d\n", + irq, fsl_qdma->irq_base); + } + + block = fsl_qdma->block_base + + FSL_QDMA_BLOCK_BASE_OFFSET(fsl_qdma, id); + + intr = qdma_readl(fsl_qdma, block + FSL_QDMA_BCQIDR(0)); + + if ((intr & FSL_QDMA_CQIDR_SQT) != 0) + intr = fsl_qdma_queue_transfer_complete(fsl_qdma, block, id); + + if (intr != 0) { + reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DMR); + reg |= FSL_QDMA_DMR_DQD; + qdma_writel(fsl_qdma, reg, ctrl + FSL_QDMA_DMR); + qdma_writel(fsl_qdma, 0, block + FSL_QDMA_BCQIER(0)); + dev_err(fsl_qdma->dma_dev.dev, "QDMA: status err!\n"); + } + + /* Clear all detected events and interrupts. */ + qdma_writel(fsl_qdma, FSL_QDMA_BCQIDR_CLEAR, + block + FSL_QDMA_BCQIDR(0)); + + return IRQ_HANDLED; +} + +static int +fsl_qdma_irq_init(struct platform_device *pdev, + struct fsl_qdma_engine *fsl_qdma) +{ + int i; + int cpu; + int ret; + char irq_name[20]; + + fsl_qdma->error_irq = + platform_get_irq_byname(pdev, "qdma-error"); + if (fsl_qdma->error_irq < 0) { + dev_err(&pdev->dev, "Can't get qdma controller irq.\n"); + return fsl_qdma->error_irq; + } + + ret = devm_request_irq(&pdev->dev, fsl_qdma->error_irq, + fsl_qdma_error_handler, 0, + "qDMA error", fsl_qdma); + if (ret) { + dev_err(&pdev->dev, "Can't register qDMA controller IRQ.\n"); + return ret; + } + + for (i = 0; i < fsl_qdma->block_number; i++) { + sprintf(irq_name, "qdma-queue%d", i); + fsl_qdma->queue_irq[i] = + platform_get_irq_byname(pdev, irq_name); + + if (fsl_qdma->queue_irq[i] < 0) { + dev_err(&pdev->dev, + "Can't get qdma queue %d irq.\n", i); + return fsl_qdma->queue_irq[i]; + } + + ret = devm_request_irq(&pdev->dev, + fsl_qdma->queue_irq[i], + fsl_qdma_queue_handler, + 0, + "qDMA queue", + fsl_qdma); + if (ret) { + dev_err(&pdev->dev, + "Can't register qDMA queue IRQ.\n"); + return ret; + } + + cpu = i % num_online_cpus(); + ret = irq_set_affinity_hint(fsl_qdma->queue_irq[i], + get_cpu_mask(cpu)); + if (ret) { + dev_err(&pdev->dev, + "Can't set cpu %d affinity to IRQ %d.\n", + cpu, + fsl_qdma->queue_irq[i]); + return ret; + } + } + + return 0; +} + +static void fsl_qdma_irq_exit(struct platform_device *pdev, + struct fsl_qdma_engine *fsl_qdma) +{ + int i; + + devm_free_irq(&pdev->dev, fsl_qdma->error_irq, fsl_qdma); + for (i = 0; i < fsl_qdma->block_number; i++) + devm_free_irq(&pdev->dev, fsl_qdma->queue_irq[i], fsl_qdma); +} + +static int fsl_qdma_reg_init(struct fsl_qdma_engine *fsl_qdma) +{ + u32 reg; + int i, j, ret; + struct fsl_qdma_queue *temp; + void __iomem *status = fsl_qdma->status_base; + void __iomem *block, *ctrl = fsl_qdma->ctrl_base; + struct fsl_qdma_queue *fsl_queue = fsl_qdma->queue; + + /* Try to halt the qDMA engine first. */ + ret = fsl_qdma_halt(fsl_qdma); + if (ret) { + dev_err(fsl_qdma->dma_dev.dev, "DMA halt failed!"); + return ret; + } + + for (i = 0; i < fsl_qdma->block_number; i++) { + /* + * Clear the command queue interrupt detect register for + * all queues. + */ + + block = fsl_qdma->block_base + + FSL_QDMA_BLOCK_BASE_OFFSET(fsl_qdma, i); + qdma_writel(fsl_qdma, FSL_QDMA_BCQIDR_CLEAR, + block + FSL_QDMA_BCQIDR(0)); + } + + for (j = 0; j < fsl_qdma->block_number; j++) { + block = fsl_qdma->block_base + + FSL_QDMA_BLOCK_BASE_OFFSET(fsl_qdma, j); + for (i = 0; i < fsl_qdma->n_queues; i++) { + temp = fsl_queue + i + (j * fsl_qdma->n_queues); + /* + * Initialize Command Queue registers to + * point to the first + * command descriptor in memory. + * Dequeue Pointer Address Registers + * Enqueue Pointer Address Registers + */ + + qdma_writel(fsl_qdma, temp->bus_addr, + block + FSL_QDMA_BCQDPA_SADDR(i)); + qdma_writel(fsl_qdma, temp->bus_addr, + block + FSL_QDMA_BCQEPA_SADDR(i)); + + /* Initialize the queue mode. */ + reg = FSL_QDMA_BCQMR_EN; + reg |= FSL_QDMA_BCQMR_CD_THLD(ilog2(temp->n_cq) - 4); + reg |= FSL_QDMA_BCQMR_CQ_SIZE(ilog2(temp->n_cq) - 6); + qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BCQMR(i)); + } + + /* + * Workaround for erratum: ERR010812. + * We must enable XOFF to avoid the enqueue rejection occurs. + * Setting SQCCMR ENTER_WM to 0x20. + */ + + qdma_writel(fsl_qdma, FSL_QDMA_SQCCMR_ENTER_WM, + block + FSL_QDMA_SQCCMR); + + /* + * Initialize status queue registers to point to the first + * command descriptor in memory. + * Dequeue Pointer Address Registers + * Enqueue Pointer Address Registers + */ + + qdma_writel(fsl_qdma, fsl_qdma->status[j]->bus_addr, + block + FSL_QDMA_SQEPAR); + qdma_writel(fsl_qdma, fsl_qdma->status[j]->bus_addr, + block + FSL_QDMA_SQDPAR); + /* Initialize status queue interrupt. */ + qdma_writel(fsl_qdma, FSL_QDMA_BCQIER_CQTIE, + block + FSL_QDMA_BCQIER(0)); + qdma_writel(fsl_qdma, FSL_QDMA_BSQICR_ICEN | + FSL_QDMA_BSQICR_ICST(5) | 0x8000, + block + FSL_QDMA_BSQICR); + qdma_writel(fsl_qdma, FSL_QDMA_CQIER_MEIE | + FSL_QDMA_CQIER_TEIE, + block + FSL_QDMA_CQIER); + + /* Initialize the status queue mode. */ + reg = FSL_QDMA_BSQMR_EN; + reg |= FSL_QDMA_BSQMR_CQ_SIZE(ilog2 + (fsl_qdma->status[j]->n_cq) - 6); + + qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); + reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR); + } + + /* Initialize controller interrupt register. */ + qdma_writel(fsl_qdma, FSL_QDMA_DEDR_CLEAR, status + FSL_QDMA_DEDR); + qdma_writel(fsl_qdma, FSL_QDMA_DEIER_CLEAR, status + FSL_QDMA_DEIER); + + reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DMR); + reg &= ~FSL_QDMA_DMR_DQD; + qdma_writel(fsl_qdma, reg, ctrl + FSL_QDMA_DMR); + + return 0; +} + +static struct dma_async_tx_descriptor * +fsl_qdma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, + dma_addr_t src, size_t len, unsigned long flags) +{ + struct fsl_qdma_comp *fsl_comp; + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + + fsl_comp = fsl_qdma_request_enqueue_desc(fsl_chan); + + if (!fsl_comp) + return NULL; + + fsl_qdma_comp_fill_memcpy(fsl_comp, dst, src, len); + + return vchan_tx_prep(&fsl_chan->vchan, &fsl_comp->vdesc, flags); +} + +static void fsl_qdma_enqueue_desc(struct fsl_qdma_chan *fsl_chan) +{ + u32 reg; + struct virt_dma_desc *vdesc; + struct fsl_qdma_comp *fsl_comp; + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue; + void __iomem *block = fsl_queue->block_base; + + reg = qdma_readl(fsl_chan->qdma, block + FSL_QDMA_BCQSR(fsl_queue->id)); + if (reg & (FSL_QDMA_BCQSR_QF | FSL_QDMA_BCQSR_XOFF)) + return; + vdesc = vchan_next_desc(&fsl_chan->vchan); + if (!vdesc) + return; + list_del(&vdesc->node); + fsl_comp = to_fsl_qdma_comp(vdesc); + + memcpy(fsl_queue->virt_head++, + fsl_comp->virt_addr, sizeof(struct fsl_qdma_format)); + if (fsl_queue->virt_head == fsl_queue->cq + fsl_queue->n_cq) + fsl_queue->virt_head = fsl_queue->cq; + + list_add_tail(&fsl_comp->list, &fsl_queue->comp_used); + barrier(); + reg = qdma_readl(fsl_chan->qdma, block + FSL_QDMA_BCQMR(fsl_queue->id)); + reg |= FSL_QDMA_BCQMR_EI; + qdma_writel(fsl_chan->qdma, reg, block + FSL_QDMA_BCQMR(fsl_queue->id)); + fsl_chan->status = DMA_IN_PROGRESS; +} + +static void fsl_qdma_free_desc(struct virt_dma_desc *vdesc) +{ + unsigned long flags; + struct fsl_qdma_comp *fsl_comp; + struct fsl_qdma_queue *fsl_queue; + + fsl_comp = to_fsl_qdma_comp(vdesc); + fsl_queue = fsl_comp->qchan->queue; + + spin_lock_irqsave(&fsl_queue->queue_lock, flags); + list_add_tail(&fsl_comp->list, &fsl_queue->comp_free); + spin_unlock_irqrestore(&fsl_queue->queue_lock, flags); +} + +static void fsl_qdma_issue_pending(struct dma_chan *chan) +{ + unsigned long flags; + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue; + + spin_lock_irqsave(&fsl_queue->queue_lock, flags); + spin_lock(&fsl_chan->vchan.lock); + if (vchan_issue_pending(&fsl_chan->vchan)) + fsl_qdma_enqueue_desc(fsl_chan); + spin_unlock(&fsl_chan->vchan.lock); + spin_unlock_irqrestore(&fsl_queue->queue_lock, flags); +} + +static void fsl_qdma_synchronize(struct dma_chan *chan) +{ + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + + vchan_synchronize(&fsl_chan->vchan); +} + +static int fsl_qdma_terminate_all(struct dma_chan *chan) +{ + LIST_HEAD(head); + unsigned long flags; + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + vchan_get_all_descriptors(&fsl_chan->vchan, &head); + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + vchan_dma_desc_free_list(&fsl_chan->vchan, &head); + return 0; +} + +static int fsl_qdma_alloc_chan_resources(struct dma_chan *chan) +{ + int ret; + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + struct fsl_qdma_engine *fsl_qdma = fsl_chan->qdma; + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue; + + if (fsl_queue->comp_pool && fsl_queue->desc_pool) + return fsl_qdma->desc_allocated; + + INIT_LIST_HEAD(&fsl_queue->comp_free); + + /* + * The dma pool for queue command buffer + */ + fsl_queue->comp_pool = + dma_pool_create("comp_pool", + chan->device->dev, + FSL_QDMA_COMMAND_BUFFER_SIZE, + 64, 0); + if (!fsl_queue->comp_pool) + return -ENOMEM; + + /* + * The dma pool for Descriptor(SD/DD) buffer + */ + fsl_queue->desc_pool = + dma_pool_create("desc_pool", + chan->device->dev, + FSL_QDMA_DESCRIPTOR_BUFFER_SIZE, + 32, 0); + if (!fsl_queue->desc_pool) + goto err_desc_pool; + + ret = fsl_qdma_pre_request_enqueue_desc(fsl_queue); + if (ret) { + dev_err(chan->device->dev, + "failed to alloc dma buffer for S/G descriptor\n"); + goto err_mem; + } + + fsl_qdma->desc_allocated++; + return fsl_qdma->desc_allocated; + +err_mem: + dma_pool_destroy(fsl_queue->desc_pool); +err_desc_pool: + dma_pool_destroy(fsl_queue->comp_pool); + return -ENOMEM; +} + +static int fsl_qdma_probe(struct platform_device *pdev) +{ + int ret, i; + int blk_num, blk_off; + u32 len, chans, queues; + struct resource *res; + struct fsl_qdma_chan *fsl_chan; + struct fsl_qdma_engine *fsl_qdma; + struct device_node *np = pdev->dev.of_node; + + ret = of_property_read_u32(np, "dma-channels", &chans); + if (ret) { + dev_err(&pdev->dev, "Can't get dma-channels.\n"); + return ret; + } + + ret = of_property_read_u32(np, "block-offset", &blk_off); + if (ret) { + dev_err(&pdev->dev, "Can't get block-offset.\n"); + return ret; + } + + ret = of_property_read_u32(np, "block-number", &blk_num); + if (ret) { + dev_err(&pdev->dev, "Can't get block-number.\n"); + return ret; + } + + blk_num = min_t(int, blk_num, num_online_cpus()); + + len = sizeof(*fsl_qdma); + fsl_qdma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!fsl_qdma) + return -ENOMEM; + + len = sizeof(*fsl_chan) * chans; + fsl_qdma->chans = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!fsl_qdma->chans) + return -ENOMEM; + + len = sizeof(struct fsl_qdma_queue *) * blk_num; + fsl_qdma->status = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!fsl_qdma->status) + return -ENOMEM; + + len = sizeof(int) * blk_num; + fsl_qdma->queue_irq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!fsl_qdma->queue_irq) + return -ENOMEM; + + ret = of_property_read_u32(np, "fsl,dma-queues", &queues); + if (ret) { + dev_err(&pdev->dev, "Can't get queues.\n"); + return ret; + } + + fsl_qdma->desc_allocated = 0; + fsl_qdma->n_chans = chans; + fsl_qdma->n_queues = queues; + fsl_qdma->block_number = blk_num; + fsl_qdma->block_offset = blk_off; + + mutex_init(&fsl_qdma->fsl_qdma_mutex); + + for (i = 0; i < fsl_qdma->block_number; i++) { + fsl_qdma->status[i] = fsl_qdma_prep_status_queue(pdev); + if (!fsl_qdma->status[i]) + return -ENOMEM; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fsl_qdma->ctrl_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fsl_qdma->ctrl_base)) + return PTR_ERR(fsl_qdma->ctrl_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + fsl_qdma->status_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fsl_qdma->status_base)) + return PTR_ERR(fsl_qdma->status_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + fsl_qdma->block_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fsl_qdma->block_base)) + return PTR_ERR(fsl_qdma->block_base); + fsl_qdma->queue = fsl_qdma_alloc_queue_resources(pdev, fsl_qdma); + if (!fsl_qdma->queue) + return -ENOMEM; + + ret = fsl_qdma_irq_init(pdev, fsl_qdma); + if (ret) + return ret; + + fsl_qdma->irq_base = platform_get_irq_byname(pdev, "qdma-queue0"); + fsl_qdma->feature = of_property_read_bool(np, "big-endian"); + INIT_LIST_HEAD(&fsl_qdma->dma_dev.channels); + + for (i = 0; i < fsl_qdma->n_chans; i++) { + struct fsl_qdma_chan *fsl_chan = &fsl_qdma->chans[i]; + + fsl_chan->qdma = fsl_qdma; + fsl_chan->queue = fsl_qdma->queue + i % (fsl_qdma->n_queues * + fsl_qdma->block_number); + fsl_chan->vchan.desc_free = fsl_qdma_free_desc; + vchan_init(&fsl_chan->vchan, &fsl_qdma->dma_dev); + } + + dma_cap_set(DMA_MEMCPY, fsl_qdma->dma_dev.cap_mask); + + fsl_qdma->dma_dev.dev = &pdev->dev; + fsl_qdma->dma_dev.device_free_chan_resources = + fsl_qdma_free_chan_resources; + fsl_qdma->dma_dev.device_alloc_chan_resources = + fsl_qdma_alloc_chan_resources; + fsl_qdma->dma_dev.device_tx_status = dma_cookie_status; + fsl_qdma->dma_dev.device_prep_dma_memcpy = fsl_qdma_prep_memcpy; + fsl_qdma->dma_dev.device_issue_pending = fsl_qdma_issue_pending; + fsl_qdma->dma_dev.device_synchronize = fsl_qdma_synchronize; + fsl_qdma->dma_dev.device_terminate_all = fsl_qdma_terminate_all; + + dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)); + + platform_set_drvdata(pdev, fsl_qdma); + + ret = dma_async_device_register(&fsl_qdma->dma_dev); + if (ret) { + dev_err(&pdev->dev, + "Can't register NXP Layerscape qDMA engine.\n"); + return ret; + } + + ret = fsl_qdma_reg_init(fsl_qdma); + if (ret) { + dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n"); + return ret; + } + + return 0; +} + +static void fsl_qdma_cleanup_vchan(struct dma_device *dmadev) +{ + struct fsl_qdma_chan *chan, *_chan; + + list_for_each_entry_safe(chan, _chan, + &dmadev->channels, vchan.chan.device_node) { + list_del(&chan->vchan.chan.device_node); + tasklet_kill(&chan->vchan.task); + } +} + +static int fsl_qdma_remove(struct platform_device *pdev) +{ + int i; + struct fsl_qdma_queue *status; + struct device_node *np = pdev->dev.of_node; + struct fsl_qdma_engine *fsl_qdma = platform_get_drvdata(pdev); + + fsl_qdma_irq_exit(pdev, fsl_qdma); + fsl_qdma_cleanup_vchan(&fsl_qdma->dma_dev); + of_dma_controller_free(np); + dma_async_device_unregister(&fsl_qdma->dma_dev); + + for (i = 0; i < fsl_qdma->block_number; i++) { + status = fsl_qdma->status[i]; + dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_format) * + status->n_cq, status->cq, status->bus_addr); + } + return 0; +} + +static const struct of_device_id fsl_qdma_dt_ids[] = { + { .compatible = "fsl,ls1021a-qdma", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_qdma_dt_ids); + +static struct platform_driver fsl_qdma_driver = { + .driver = { + .name = "fsl-qdma", + .of_match_table = fsl_qdma_dt_ids, + }, + .probe = fsl_qdma_probe, + .remove = fsl_qdma_remove, +}; + +module_platform_driver(fsl_qdma_driver); + +MODULE_ALIAS("platform:fsl-qdma"); +MODULE_DESCRIPTION("NXP Layerscape qDMA engine driver"); -- cgit v1.2.3 From 279cc97c01a20477fe33b6705abff8a186761a8a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 10 Dec 2018 21:55:02 +0100 Subject: dmaengine: fsl-qdma: add MODULE_LICENSE The newly added driver lacks a MODULE_LICENSE tag, which now produces a warning: WARNING: modpost: missing MODULE_LICENSE() in drivers/dma/fsl-qdma.o Add the license according to the SPDX specifier. Fixes: 75628c149b0d ("dmaengine: fsl-qdma: Add qDMA controller driver for Layerscape SoCs") Signed-off-by: Arnd Bergmann Signed-off-by: Vinod Koul --- drivers/dma/fsl-qdma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index c18e3492090b..aa1d0ae3d207 100644 --- a/drivers/dma/fsl-qdma.c +++ b/drivers/dma/fsl-qdma.c @@ -1255,4 +1255,5 @@ static struct platform_driver fsl_qdma_driver = { module_platform_driver(fsl_qdma_driver); MODULE_ALIAS("platform:fsl-qdma"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("NXP Layerscape qDMA engine driver"); -- cgit v1.2.3 From 7c97381e7a9a5ec359007c0d491a143e3d9f787c Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Mon, 24 Dec 2018 11:41:54 -0600 Subject: dmaengine: mv_xor: Fix a missing check in mv_xor_channel_add dma_async_device_register() may fail and return an error. The capabilities checked in mv_xor_channel_add() are not complete. The fix handles the error by freeing the resources. Signed-off-by: Aditya Pakki Signed-off-by: Vinod Koul --- drivers/dma/mv_xor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 7f595355fb79..e733c5eeaabc 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1153,7 +1153,10 @@ mv_xor_channel_add(struct mv_xor_device *xordev, dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "", dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : ""); - dma_async_device_register(dma_dev); + ret = dma_async_device_register(dma_dev); + if (ret) + goto err_free_irq; + return mv_chan; err_free_irq: -- cgit v1.2.3 From a474b3f0428d6b02a538aa10b3c3b722751cb382 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Fri, 28 Dec 2018 14:11:19 -0600 Subject: dmaengine: qcom_hidma: Check for driver register failure While initializing the driver, the function platform_driver_register can fail and return an error. Consistent with other invocations, this patch returns the error upstream. Signed-off-by: Aditya Pakki Acked-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_mgmt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index d64edeb6771a..681de12f4c67 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -423,9 +423,8 @@ static int __init hidma_mgmt_init(void) hidma_mgmt_of_populate_channels(child); } #endif - platform_driver_register(&hidma_mgmt_driver); + return platform_driver_register(&hidma_mgmt_driver); - return 0; } module_init(hidma_mgmt_init); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 906b40b246b0acb54c4dc97e815cf734761c9820 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Fri, 28 Dec 2018 13:26:41 -0600 Subject: dmaengine: stm32-mdma: Add a check on read_u32_array In stm32_mdma_probe, after reading the property "st,ahb-addr-masks", the second call is not checked for failure. This time of check to time of use case of "count" error is sent upstream. Signed-off-by: Aditya Pakki Acked-by: Pierre-Yves MORDRET Signed-off-by: Vinod Koul --- drivers/dma/stm32-mdma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 390e4cae0e1a..485dea177704 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1579,9 +1579,11 @@ static int stm32_mdma_probe(struct platform_device *pdev) dmadev->nr_channels = nr_channels; dmadev->nr_requests = nr_requests; - device_property_read_u32_array(&pdev->dev, "st,ahb-addr-masks", + ret = device_property_read_u32_array(&pdev->dev, "st,ahb-addr-masks", dmadev->ahb_addr_masks, count); + if (ret) + return ret; dmadev->nr_ahb_addr_masks = count; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3 From ca4c72c01e349ff6313ced02e8e66f8e691530a9 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Thu, 3 Jan 2019 11:17:29 +0100 Subject: dmaengine: stm32-dma: check FIFO error interrupt enable For avoiding false FIFO detection, check FIFO Error interrupt is enabled prior raising any errors. This will prevent having spurious FIFO error where it shouldn't. Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 4903a408fc14..48f7c0fc1af9 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -641,12 +641,13 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) { struct stm32_dma_chan *chan = devid; struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); - u32 status, scr; + u32 status, scr, sfcr; spin_lock(&chan->vchan.lock); status = stm32_dma_irq_status(chan); scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); + sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); if (status & STM32_DMA_TCI) { stm32_dma_irq_clear(chan, STM32_DMA_TCI); @@ -661,10 +662,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) if (status & STM32_DMA_FEI) { stm32_dma_irq_clear(chan, STM32_DMA_FEI); status &= ~STM32_DMA_FEI; - if (!(scr & STM32_DMA_SCR_EN)) - dev_err(chan2dev(chan), "FIFO Error\n"); - else - dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); + if (sfcr & STM32_DMA_SFCR_FEIE) { + if (!(scr & STM32_DMA_SCR_EN)) + dev_err(chan2dev(chan), "FIFO Error\n"); + else + dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); + } } if (status) { stm32_dma_irq_clear(chan, status); -- cgit v1.2.3 From 48bc73ba14bcd4080d971ed7049e81f2a4f4302e Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Thu, 3 Jan 2019 11:17:08 +0100 Subject: dmaengine: stm32-dma: Add PM Runtime support Use pm_runtime engine for clock management purpose. Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 58 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 48f7c0fc1af9..ba239b529fa9 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1115,15 +1116,14 @@ static int stm32_dma_alloc_chan_resources(struct dma_chan *c) int ret; chan->config_init = false; - ret = clk_prepare_enable(dmadev->clk); - if (ret < 0) { - dev_err(chan2dev(chan), "clk_prepare_enable failed: %d\n", ret); + + ret = pm_runtime_get_sync(dmadev->ddev.dev); + if (ret < 0) return ret; - } ret = stm32_dma_disable_chan(chan); if (ret < 0) - clk_disable_unprepare(dmadev->clk); + pm_runtime_put(dmadev->ddev.dev); return ret; } @@ -1143,7 +1143,7 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) spin_unlock_irqrestore(&chan->vchan.lock, flags); } - clk_disable_unprepare(dmadev->clk); + pm_runtime_put(dmadev->ddev.dev); vchan_free_chan_resources(to_virt_chan(c)); } @@ -1243,6 +1243,12 @@ static int stm32_dma_probe(struct platform_device *pdev) return PTR_ERR(dmadev->clk); } + ret = clk_prepare_enable(dmadev->clk); + if (ret < 0) { + dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret); + return ret; + } + dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node, "st,mem2mem"); @@ -1292,7 +1298,7 @@ static int stm32_dma_probe(struct platform_device *pdev) ret = dma_async_device_register(dd); if (ret) - return ret; + goto clk_free; for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { chan = &dmadev->chan[i]; @@ -1324,20 +1330,58 @@ static int stm32_dma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dmadev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_put(&pdev->dev); + dev_info(&pdev->dev, "STM32 DMA driver registered\n"); return 0; err_unregister: dma_async_device_unregister(dd); +clk_free: + clk_disable_unprepare(dmadev->clk); return ret; } +#ifdef CONFIG_PM +static int stm32_dma_runtime_suspend(struct device *dev) +{ + struct stm32_dma_device *dmadev = dev_get_drvdata(dev); + + clk_disable_unprepare(dmadev->clk); + + return 0; +} + +static int stm32_dma_runtime_resume(struct device *dev) +{ + struct stm32_dma_device *dmadev = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(dmadev->clk); + if (ret) { + dev_err(dev, "failed to prepare_enable clock\n"); + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops stm32_dma_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend, + stm32_dma_runtime_resume, NULL) +}; + static struct platform_driver stm32_dma_driver = { .driver = { .name = "stm32-dma", .of_match_table = stm32_dma_of_match, + .pm = &stm32_dma_pm_ops, }, }; -- cgit v1.2.3 From 4f3ceca254e0fa75ccb9c716480f9b30e1f6c0e9 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Thu, 3 Jan 2019 11:17:09 +0100 Subject: dmaengine: stm32-dmamux: Add PM Runtime support Use pm_runtime engine for clock management purpose. Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Vinod Koul --- drivers/dma/stm32-dmamux.c | 58 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c index b922db90939a..a67119199c45 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -79,8 +80,7 @@ static void stm32_dmamux_free(struct device *dev, void *route_data) stm32_dmamux_write(dmamux->iomem, STM32_DMAMUX_CCR(mux->chan_id), 0); clear_bit(mux->chan_id, dmamux->dma_inuse); - if (!IS_ERR(dmamux->clk)) - clk_disable(dmamux->clk); + pm_runtime_put_sync(dev); spin_unlock_irqrestore(&dmamux->lock, flags); @@ -146,13 +146,10 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, /* Set dma request */ spin_lock_irqsave(&dmamux->lock, flags); - if (!IS_ERR(dmamux->clk)) { - ret = clk_enable(dmamux->clk); - if (ret < 0) { - spin_unlock_irqrestore(&dmamux->lock, flags); - dev_err(&pdev->dev, "clk_prep_enable issue: %d\n", ret); - goto error; - } + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + spin_unlock_irqrestore(&dmamux->lock, flags); + goto error; } spin_unlock_irqrestore(&dmamux->lock, flags); @@ -254,6 +251,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "DMAMUX defaulting on %u requests\n", stm32_dmamux->dmamux_requests); } + pm_runtime_get_noresume(&pdev->dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iomem = devm_ioremap_resource(&pdev->dev, res); @@ -282,6 +280,8 @@ static int stm32_dmamux_probe(struct platform_device *pdev) stm32_dmamux->dmarouter.route_free = stm32_dmamux_free; platform_set_drvdata(pdev, stm32_dmamux); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); if (!IS_ERR(stm32_dmamux->clk)) { ret = clk_prepare_enable(stm32_dmamux->clk); @@ -291,17 +291,52 @@ static int stm32_dmamux_probe(struct platform_device *pdev) } } + pm_runtime_get_noresume(&pdev->dev); + /* Reset the dmamux */ for (i = 0; i < stm32_dmamux->dma_requests; i++) stm32_dmamux_write(stm32_dmamux->iomem, STM32_DMAMUX_CCR(i), 0); - if (!IS_ERR(stm32_dmamux->clk)) - clk_disable(stm32_dmamux->clk); + pm_runtime_put(&pdev->dev); return of_dma_router_register(node, stm32_dmamux_route_allocate, &stm32_dmamux->dmarouter); } +#ifdef CONFIG_PM +static int stm32_dmamux_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + struct stm32_dmamux_data *stm32_dmamux = platform_get_drvdata(pdev); + + clk_disable_unprepare(stm32_dmamux->clk); + + return 0; +} + +static int stm32_dmamux_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + struct stm32_dmamux_data *stm32_dmamux = platform_get_drvdata(pdev); + int ret; + + ret = clk_prepare_enable(stm32_dmamux->clk); + if (ret) { + dev_err(&pdev->dev, "failed to prepare_enable clock\n"); + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops stm32_dmamux_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_dmamux_runtime_suspend, + stm32_dmamux_runtime_resume, NULL) +}; + static const struct of_device_id stm32_dmamux_match[] = { { .compatible = "st,stm32h7-dmamux" }, {}, @@ -312,6 +347,7 @@ static struct platform_driver stm32_dmamux_driver = { .driver = { .name = "stm32-dmamux", .of_match_table = stm32_dmamux_match, + .pm = &stm32_dmamux_pm_ops, }, }; -- cgit v1.2.3 From 89e987e3b4d6b87b2b12c3bdfc90bfef16e68b4e Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Thu, 3 Jan 2019 11:17:10 +0100 Subject: dmaengine: stm32-mdma: Add PM Runtime support Use pm_runtime engine for clock management purpose Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Vinod Koul --- drivers/dma/stm32-mdma.c | 52 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 485dea177704..4e0eede599a8 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1456,15 +1457,13 @@ static int stm32_mdma_alloc_chan_resources(struct dma_chan *c) return -ENOMEM; } - ret = clk_prepare_enable(dmadev->clk); - if (ret < 0) { - dev_err(chan2dev(chan), "clk_prepare_enable failed: %d\n", ret); + ret = pm_runtime_get_sync(dmadev->ddev.dev); + if (ret < 0) return ret; - } ret = stm32_mdma_disable_chan(chan); if (ret < 0) - clk_disable_unprepare(dmadev->clk); + pm_runtime_put(dmadev->ddev.dev); return ret; } @@ -1484,7 +1483,7 @@ static void stm32_mdma_free_chan_resources(struct dma_chan *c) spin_unlock_irqrestore(&chan->vchan.lock, flags); } - clk_disable_unprepare(dmadev->clk); + pm_runtime_put(dmadev->ddev.dev); vchan_free_chan_resources(to_virt_chan(c)); dmam_pool_destroy(chan->desc_pool); chan->desc_pool = NULL; @@ -1599,6 +1598,12 @@ static int stm32_mdma_probe(struct platform_device *pdev) return ret; } + ret = clk_prepare_enable(dmadev->clk); + if (ret < 0) { + dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret); + return ret; + } + dmadev->rst = devm_reset_control_get(&pdev->dev, NULL); if (!IS_ERR(dmadev->rst)) { reset_control_assert(dmadev->rst); @@ -1670,6 +1675,10 @@ static int stm32_mdma_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, dmadev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_put(&pdev->dev); dev_info(&pdev->dev, "STM32 MDMA driver registered\n"); @@ -1679,11 +1688,42 @@ err_unregister: return ret; } +#ifdef CONFIG_PM +static int stm32_mdma_runtime_suspend(struct device *dev) +{ + struct stm32_mdma_device *dmadev = dev_get_drvdata(dev); + + clk_disable_unprepare(dmadev->clk); + + return 0; +} + +static int stm32_mdma_runtime_resume(struct device *dev) +{ + struct stm32_mdma_device *dmadev = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(dmadev->clk); + if (ret) { + dev_err(dev, "failed to prepare_enable clock\n"); + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops stm32_mdma_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_mdma_runtime_suspend, + stm32_mdma_runtime_resume, NULL) +}; + static struct platform_driver stm32_mdma_driver = { .probe = stm32_mdma_probe, .driver = { .name = "stm32-mdma", .of_match_table = stm32_mdma_of_match, + .pm = &stm32_mdma_pm_ops, }, }; -- cgit v1.2.3 From e486df39305864604b7e25f2a95d51039517ac57 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 21 Nov 2018 16:13:19 +0000 Subject: dmaengine: tegra: avoid overflow of byte tracking The dma_desc->bytes_transferred counter tracks the number of bytes moved by the DMA channel. This is then used to calculate the information passed back in the in the tegra_dma_tx_status callback, which is usually fine. When the DMA channel is configured as continous, then the bytes_transferred counter will increase over time and eventually overflow to become negative so the residue count will become invalid and the ALSA sound-dma code will report invalid hardware pointer values to the application. This results in some users becoming confused about the playout position and putting audio data in the wrong place. To fix this issue, always ensure the bytes_transferred field is modulo the size of the request. We only do this for the case of the cyclic transfer done ISR as anyone attempting to move 2GiB of DMA data in one transfer is unlikely. Note, we don't fix the issue that we should /never/ transfer a negative number of bytes so we could make those fields unsigned. Reviewed-by: Dmitry Osipenko Signed-off-by: Ben Dooks Acked-by: Jon Hunter Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 9a558e30c461..8219ab88a507 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -636,7 +636,10 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc, sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node); dma_desc = sgreq->dma_desc; - dma_desc->bytes_transferred += sgreq->req_len; + /* if we dma for long enough the transfer count will wrap */ + dma_desc->bytes_transferred = + (dma_desc->bytes_transferred + sgreq->req_len) % + dma_desc->bytes_requested; /* Callback need to be call */ if (!dma_desc->cb_count) -- cgit v1.2.3 From 216a1d7da0660dd7d5f79c48e117de8d8d2da468 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 21 Nov 2018 16:13:20 +0000 Subject: dmaengine: tegra: make byte counters unsigned int The buffer byte request length and counter are declared as signed integers but the values should never be below zero, so make these unsigned integers instead. Reviewed-by: Dmitry Osipenko Signed-off-by: Ben Dooks Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 8219ab88a507..adfd918baedc 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -155,7 +155,7 @@ struct tegra_dma_channel_regs { */ struct tegra_dma_sg_req { struct tegra_dma_channel_regs ch_regs; - int req_len; + unsigned int req_len; bool configured; bool last_sg; struct list_head node; @@ -169,8 +169,8 @@ struct tegra_dma_sg_req { */ struct tegra_dma_desc { struct dma_async_tx_descriptor txd; - int bytes_requested; - int bytes_transferred; + unsigned int bytes_requested; + unsigned int bytes_transferred; enum dma_status dma_status; struct list_head node; struct list_head tx_list; -- cgit v1.2.3 From 547b311cf7ecf778adc1979b06eda854429946b6 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 21 Nov 2018 16:13:21 +0000 Subject: dmaengine: tegra: fix incorrect case of DMA The use of Dma is annoying, since it is an acronym so should be all upper case. Fix this throughout the driver. Reviewed-by: Dmitry Osipenko Signed-off-by: Ben Dooks Acked-by: Jon Hunter Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index adfd918baedc..ec8938a2ecab 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -146,7 +146,7 @@ struct tegra_dma_channel_regs { }; /* - * tegra_dma_sg_req: Dma request details to configure hardware. This + * tegra_dma_sg_req: DMA request details to configure hardware. This * contains the details for one transfer to configure DMA hw. * The client's request for data transfer can be broken into multiple * sub-transfer as per requester details and hw support. @@ -574,7 +574,7 @@ static bool handle_continuous_head_request(struct tegra_dma_channel *tdc, struct tegra_dma_sg_req *hsgreq = NULL; if (list_empty(&tdc->pending_sg_req)) { - dev_err(tdc2dev(tdc), "Dma is running without req\n"); + dev_err(tdc2dev(tdc), "DMA is running without req\n"); tegra_dma_stop(tdc); return false; } @@ -587,7 +587,7 @@ static bool handle_continuous_head_request(struct tegra_dma_channel *tdc, hsgreq = list_first_entry(&tdc->pending_sg_req, typeof(*hsgreq), node); if (!hsgreq->configured) { tegra_dma_stop(tdc); - dev_err(tdc2dev(tdc), "Error in dma transfer, aborting dma\n"); + dev_err(tdc2dev(tdc), "Error in DMA transfer, aborting DMA\n"); tegra_dma_abort_all(tdc); return false; } @@ -922,7 +922,7 @@ static int get_transfer_param(struct tegra_dma_channel *tdc, return 0; default: - dev_err(tdc2dev(tdc), "Dma direction is not supported\n"); + dev_err(tdc2dev(tdc), "DMA direction is not supported\n"); return -EINVAL; } return -EINVAL; @@ -955,7 +955,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( enum dma_slave_buswidth slave_bw; if (!tdc->config_init) { - dev_err(tdc2dev(tdc), "dma channel is not configured\n"); + dev_err(tdc2dev(tdc), "DMA channel is not configured\n"); return NULL; } if (sg_len < 1) { @@ -988,7 +988,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( dma_desc = tegra_dma_desc_get(tdc); if (!dma_desc) { - dev_err(tdc2dev(tdc), "Dma descriptors not available\n"); + dev_err(tdc2dev(tdc), "DMA descriptors not available\n"); return NULL; } INIT_LIST_HEAD(&dma_desc->tx_list); @@ -1008,14 +1008,14 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( if ((len & 3) || (mem & 3) || (len > tdc->tdma->chip_data->max_dma_count)) { dev_err(tdc2dev(tdc), - "Dma length/memory address is not supported\n"); + "DMA length/memory address is not supported\n"); tegra_dma_desc_put(tdc, dma_desc); return NULL; } sg_req = tegra_dma_sg_req_get(tdc); if (!sg_req) { - dev_err(tdc2dev(tdc), "Dma sg-req not available\n"); + dev_err(tdc2dev(tdc), "DMA sg-req not available\n"); tegra_dma_desc_put(tdc, dma_desc); return NULL; } @@ -1090,7 +1090,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( * terminating the DMA. */ if (tdc->busy) { - dev_err(tdc2dev(tdc), "Request not allowed when dma running\n"); + dev_err(tdc2dev(tdc), "Request not allowed when DMA running\n"); return NULL; } @@ -1147,7 +1147,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( while (remain_len) { sg_req = tegra_dma_sg_req_get(tdc); if (!sg_req) { - dev_err(tdc2dev(tdc), "Dma sg-req not available\n"); + dev_err(tdc2dev(tdc), "DMA sg-req not available\n"); tegra_dma_desc_put(tdc, dma_desc); return NULL; } -- cgit v1.2.3 From 65c383c78000f73a96869505554f57c364308204 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 21 Nov 2018 16:13:22 +0000 Subject: dmaengine: tegra: reduce channel name field size The name field is used for "apbdma.%d" which is rarely going to be more than 10 bytes, so reduce the size from 30 to 12. This is only being used by the interrupt registration, so is not critical to the operation of the driver either. Signed-off-by: Ben Dooks Acked-by: Jon Hunter Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index ec8938a2ecab..c60c3f7cad5f 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -186,7 +186,7 @@ typedef void (*dma_isr_handler)(struct tegra_dma_channel *tdc, /* tegra_dma_channel: Channel specific information */ struct tegra_dma_channel { struct dma_chan dma_chan; - char name[30]; + char name[12]; bool config_init; int id; int irq; -- cgit v1.2.3 From 95f295f9fe08166307d94b641fba0b0e924d5d31 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 21 Nov 2018 16:13:23 +0000 Subject: dmaengine: tegra: add tracepoints to driver Add some trace-points to the driver to allow for debuging via the trace pipe. Signed-off-by: Ben Dooks Reviewed-by: Steven Rostedt (VMware) Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index c60c3f7cad5f..659b49bf6fdb 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -38,6 +38,9 @@ #include "dmaengine.h" +#define CREATE_TRACE_POINTS +#include + #define TEGRA_APBDMA_GENERAL 0x0 #define TEGRA_APBDMA_GENERAL_ENABLE BIT(31) @@ -672,6 +675,8 @@ static void tegra_dma_tasklet(unsigned long data) dmaengine_desc_get_callback(&dma_desc->txd, &cb); cb_count = dma_desc->cb_count; dma_desc->cb_count = 0; + trace_tegra_dma_complete_cb(&tdc->dma_chan, cb_count, + cb.callback); spin_unlock_irqrestore(&tdc->lock, flags); while (cb_count--) dmaengine_desc_callback_invoke(&cb, NULL); @@ -688,6 +693,7 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id) spin_lock_irqsave(&tdc->lock, flags); + trace_tegra_dma_isr(&tdc->dma_chan, irq); status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS); if (status & TEGRA_APBDMA_STATUS_ISE_EOC) { tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status); @@ -846,6 +852,7 @@ found: dma_set_residue(txstate, residual); } + trace_tegra_dma_tx_status(&tdc->dma_chan, cookie, txstate); spin_unlock_irqrestore(&tdc->lock, flags); return ret; } -- cgit v1.2.3 From 616f0f81d857e248a72b5af45ab185196556ae2e Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Tue, 20 Nov 2018 16:31:45 +0100 Subject: dmaengine: xilinx_dma: commonize DMA copy size calculation This patch removes a bit of duplicated code by introducing a new function that implements calculations for DMA copy size, and prepares for changes to the copy size calculation that will happen in following patches. Suggested-by: Vinod Koul Signed-off-by: Andrea Merello Reviewed-by: Radhey Shyam Pandey Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 02880963092f..fd9f37bafab0 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -425,6 +425,7 @@ struct xilinx_dma_config { * @rxs_clk: DMA s2mm stream clock * @nr_channels: Number of channels DMA device supports * @chan_id: DMA channel identifier + * @max_buffer_len: Max buffer length */ struct xilinx_dma_device { void __iomem *regs; @@ -444,6 +445,7 @@ struct xilinx_dma_device { struct clk *rxs_clk; u32 nr_channels; u32 chan_id; + u32 max_buffer_len; }; /* Macros */ @@ -959,6 +961,25 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) return 0; } +/** + * xilinx_dma_calc_copysize - Calculate the amount of data to copy + * @chan: Driver specific DMA channel + * @size: Total data that needs to be copied + * @done: Amount of data that has been already copied + * + * Return: Amount of data that has to be copied + */ +static int xilinx_dma_calc_copysize(struct xilinx_dma_chan *chan, + int size, int done) +{ + size_t copy; + + copy = min_t(size_t, size - done, + chan->xdev->max_buffer_len); + + return copy; +} + /** * xilinx_dma_tx_status - Get DMA transaction status * @dchan: DMA channel @@ -992,7 +1013,7 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan, list_for_each_entry(segment, &desc->segments, node) { hw = &segment->hw; residue += (hw->control - hw->status) & - XILINX_DMA_MAX_TRANS_LEN; + chan->xdev->max_buffer_len; } } spin_unlock_irqrestore(&chan->lock, flags); @@ -1254,7 +1275,7 @@ static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan) /* Start the transfer */ dma_ctrl_write(chan, XILINX_DMA_REG_BTT, - hw->control & XILINX_DMA_MAX_TRANS_LEN); + hw->control & chan->xdev->max_buffer_len); } list_splice_tail_init(&chan->pending_list, &chan->active_list); @@ -1357,7 +1378,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) /* Start the transfer */ dma_ctrl_write(chan, XILINX_DMA_REG_BTT, - hw->control & XILINX_DMA_MAX_TRANS_LEN); + hw->control & chan->xdev->max_buffer_len); } list_splice_tail_init(&chan->pending_list, &chan->active_list); @@ -1718,7 +1739,7 @@ xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst, struct xilinx_cdma_tx_segment *segment; struct xilinx_cdma_desc_hw *hw; - if (!len || len > XILINX_DMA_MAX_TRANS_LEN) + if (!len || len > chan->xdev->max_buffer_len) return NULL; desc = xilinx_dma_alloc_tx_descriptor(chan); @@ -1808,8 +1829,8 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg( * Calculate the maximum number of bytes to transfer, * making sure it is less than the hw limit */ - copy = min_t(size_t, sg_dma_len(sg) - sg_used, - XILINX_DMA_MAX_TRANS_LEN); + copy = xilinx_dma_calc_copysize(chan, sg_dma_len(sg), + sg_used); hw = &segment->hw; /* Fill in the descriptor */ @@ -1913,8 +1934,8 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_dma_cyclic( * Calculate the maximum number of bytes to transfer, * making sure it is less than the hw limit */ - copy = min_t(size_t, period_len - sg_used, - XILINX_DMA_MAX_TRANS_LEN); + copy = xilinx_dma_calc_copysize(chan, period_len, + sg_used); hw = &segment->hw; xilinx_axidma_buf(chan, hw, buf_addr, sg_used, period_len * i); @@ -2628,6 +2649,8 @@ static int xilinx_dma_probe(struct platform_device *pdev) /* Retrieve the DMA engine properties from the device tree */ xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg"); + xdev->max_buffer_len = XILINX_DMA_MAX_TRANS_LEN; + if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) xdev->mcdma = of_property_read_bool(node, "xlnx,mcdma"); -- cgit v1.2.3 From 5c094d4cac5ba78139f4d7169145b57af7f07981 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Tue, 20 Nov 2018 16:31:46 +0100 Subject: dmaengine: xilinx_dma: in axidma slave_sg and dma_cyclic mode align split descriptors Whenever a single or cyclic transaction is prepared, the driver could eventually split it over several SG descriptors in order to deal with the HW maximum transfer length. This could end up in DMA operations starting from a misaligned address. This seems fatal for the HW if DRE (Data Realignment Engine) is not enabled. This patch eventually adjusts the transfer size in order to make sure all operations start from an aligned address. Cc: Radhey Shyam Pandey Signed-off-by: Andrea Merello Reviewed-by: Radhey Shyam Pandey Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index fd9f37bafab0..93435f7002ab 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -977,6 +977,15 @@ static int xilinx_dma_calc_copysize(struct xilinx_dma_chan *chan, copy = min_t(size_t, size - done, chan->xdev->max_buffer_len); + if ((copy + done < size) && + chan->xdev->common.copy_align) { + /* + * If this is not the last descriptor, make sure + * the next one will be properly aligned + */ + copy = rounddown(copy, + (1 << chan->xdev->common.copy_align)); + } return copy; } -- cgit v1.2.3 From ae809690b46a71dc56cda5b3b8884c8c41a0df15 Mon Sep 17 00:00:00 2001 From: Radhey Shyam Pandey Date: Tue, 20 Nov 2018 16:31:48 +0100 Subject: dmaengine: xilinx_dma: program hardware supported buffer length AXI-DMA IP supports configurable (c_sg_length_width) buffer length register width, hence read buffer length (xlnx,sg-length-width) DT property and ensure that driver doesn't program buffer length exceeding the supported limit. For VDMA and CDMA there is no change. Cc: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Signed-off-by: Radhey Shyam Pandey Signed-off-by: Michal Simek Signed-off-by: Andrea Merello [rebase, reword] Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 93435f7002ab..d59af2b33a99 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -161,7 +161,9 @@ #define XILINX_DMA_REG_BTT 0x28 /* AXI DMA Specific Masks/Bit fields */ -#define XILINX_DMA_MAX_TRANS_LEN GENMASK(22, 0) +#define XILINX_DMA_MAX_TRANS_LEN_MIN 8 +#define XILINX_DMA_MAX_TRANS_LEN_MAX 23 +#define XILINX_DMA_V2_MAX_TRANS_LEN_MAX 26 #define XILINX_DMA_CR_COALESCE_MAX GENMASK(23, 16) #define XILINX_DMA_CR_CYCLIC_BD_EN_MASK BIT(4) #define XILINX_DMA_CR_COALESCE_SHIFT 16 @@ -2626,7 +2628,7 @@ static int xilinx_dma_probe(struct platform_device *pdev) struct xilinx_dma_device *xdev; struct device_node *child, *np = pdev->dev.of_node; struct resource *io; - u32 num_frames, addr_width; + u32 num_frames, addr_width, len_width; int i, err; /* Allocate and initialize the DMA engine structure */ @@ -2658,10 +2660,24 @@ static int xilinx_dma_probe(struct platform_device *pdev) /* Retrieve the DMA engine properties from the device tree */ xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg"); - xdev->max_buffer_len = XILINX_DMA_MAX_TRANS_LEN; + xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0); - if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) + if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { xdev->mcdma = of_property_read_bool(node, "xlnx,mcdma"); + if (!of_property_read_u32(node, "xlnx,sg-length-width", + &len_width)) { + if (len_width < XILINX_DMA_MAX_TRANS_LEN_MIN || + len_width > XILINX_DMA_V2_MAX_TRANS_LEN_MAX) { + dev_warn(xdev->dev, + "invalid xlnx,sg-length-width property value. Using default width\n"); + } else { + if (len_width > XILINX_DMA_MAX_TRANS_LEN_MAX) + dev_warn(xdev->dev, "Please ensure that IP supports buffer length > 23 bits\n"); + xdev->max_buffer_len = + GENMASK(len_width - 1, 0); + } + } + } if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { err = of_property_read_u32(node, "xlnx,num-fstores", -- cgit v1.2.3 From 05f7ea7f6ef611a077fcbb983fb8d6a99e91e1f6 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Tue, 20 Nov 2018 16:31:49 +0100 Subject: dmaengine: xilinx_dma: autodetect whether the HW supports scatter-gather The AXIDMA and CDMA HW can be either direct-access or scatter-gather version. These are SW incompatible. The driver can handle both versions: a DT property was used to tell the driver whether to assume the HW is in scatter-gather mode. This patch makes the driver to autodetect this information. The DT property is not required anymore. No changes for VDMA. Cc: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Cc: Radhey Shyam Pandey Signed-off-by: Andrea Merello Reviewed-by: Radhey Shyam Pandey Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index d59af2b33a99..b559efe06adb 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -86,6 +86,7 @@ #define XILINX_DMA_DMASR_DMA_DEC_ERR BIT(6) #define XILINX_DMA_DMASR_DMA_SLAVE_ERR BIT(5) #define XILINX_DMA_DMASR_DMA_INT_ERR BIT(4) +#define XILINX_DMA_DMASR_SG_MASK BIT(3) #define XILINX_DMA_DMASR_IDLE BIT(1) #define XILINX_DMA_DMASR_HALTED BIT(0) #define XILINX_DMA_DMASR_DELAY_MASK GENMASK(31, 24) @@ -414,7 +415,6 @@ struct xilinx_dma_config { * @dev: Device Structure * @common: DMA device structure * @chan: Driver specific DMA channel - * @has_sg: Specifies whether Scatter-Gather is present or not * @mcdma: Specifies whether Multi-Channel is present or not * @flush_on_fsync: Flush on frame sync * @ext_addr: Indicates 64 bit addressing is supported by dma device @@ -434,7 +434,6 @@ struct xilinx_dma_device { struct device *dev; struct dma_device common; struct xilinx_dma_chan *chan[XILINX_DMA_MAX_CHANS_PER_DEVICE]; - bool has_sg; bool mcdma; u32 flush_on_fsync; bool ext_addr; @@ -2421,7 +2420,6 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, chan->dev = xdev->dev; chan->xdev = xdev; - chan->has_sg = xdev->has_sg; chan->desc_pendingcount = 0x0; chan->ext_addr = xdev->ext_addr; /* This variable ensures that descriptors are not @@ -2521,6 +2519,15 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, chan->stop_transfer = xilinx_dma_stop_transfer; } + /* check if SG is enabled (only for AXIDMA and CDMA) */ + if (xdev->dma_config->dmatype != XDMA_TYPE_VDMA) { + if (dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) & + XILINX_DMA_DMASR_SG_MASK) + chan->has_sg = true; + dev_dbg(chan->dev, "ch %d: SG %s\n", chan->id, + chan->has_sg ? "enabled" : "disabled"); + } + /* Initialize the tasklet */ tasklet_init(&chan->tasklet, xilinx_dma_do_tasklet, (unsigned long)chan); @@ -2659,7 +2666,6 @@ static int xilinx_dma_probe(struct platform_device *pdev) return PTR_ERR(xdev->regs); /* Retrieve the DMA engine properties from the device tree */ - xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg"); xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0); if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { -- cgit v1.2.3 From b8349172b4001ea4e8b38a243275aecd90aa7573 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Tue, 20 Nov 2018 16:31:51 +0100 Subject: dmaengine: xilinx_dma: Drop SG support for VDMA IP xilinx_vdma_start_transfer() is used only for VDMA IP, still it contains conditional code on has_sg variable. has_sg is set only whenever the HW does support SG mode, that is never true for VDMA IP. This patch drops the never-taken branches. Signed-off-by: Andrea Merello Reviewed-by: Radhey Shyam Pandey Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 84 ++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index b559efe06adb..d9431afa031b 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -1102,6 +1102,8 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) struct xilinx_dma_tx_descriptor *desc, *tail_desc; u32 reg, j; struct xilinx_vdma_tx_segment *tail_segment; + struct xilinx_vdma_tx_segment *segment, *last = NULL; + int i = 0; /* This function was invoked with lock held */ if (chan->err) @@ -1121,14 +1123,6 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) tail_segment = list_last_entry(&tail_desc->segments, struct xilinx_vdma_tx_segment, node); - /* - * If hardware is idle, then all descriptors on the running lists are - * done, start new transfers - */ - if (chan->has_sg) - dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC, - desc->async_tx.phys); - /* Configure the hardware using info in the config structure */ if (chan->has_vflip) { reg = dma_read(chan, XILINX_VDMA_REG_ENABLE_VERTICAL_FLIP); @@ -1145,15 +1139,11 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) else reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN; - /* - * With SG, start with circular mode, so that BDs can be fetched. - * In direct register mode, if not parking, enable circular mode - */ - if (chan->has_sg || !config->park) - reg |= XILINX_DMA_DMACR_CIRC_EN; - + /* If not parking, enable circular mode */ if (config->park) reg &= ~XILINX_DMA_DMACR_CIRC_EN; + else + reg |= XILINX_DMA_DMACR_CIRC_EN; dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg); @@ -1175,48 +1165,38 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) return; /* Start the transfer */ - if (chan->has_sg) { - dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC, - tail_segment->phys); - list_splice_tail_init(&chan->pending_list, &chan->active_list); - chan->desc_pendingcount = 0; - } else { - struct xilinx_vdma_tx_segment *segment, *last = NULL; - int i = 0; - - if (chan->desc_submitcount < chan->num_frms) - i = chan->desc_submitcount; - - list_for_each_entry(segment, &desc->segments, node) { - if (chan->ext_addr) - vdma_desc_write_64(chan, - XILINX_VDMA_REG_START_ADDRESS_64(i++), - segment->hw.buf_addr, - segment->hw.buf_addr_msb); - else - vdma_desc_write(chan, + if (chan->desc_submitcount < chan->num_frms) + i = chan->desc_submitcount; + + list_for_each_entry(segment, &desc->segments, node) { + if (chan->ext_addr) + vdma_desc_write_64(chan, + XILINX_VDMA_REG_START_ADDRESS_64(i++), + segment->hw.buf_addr, + segment->hw.buf_addr_msb); + else + vdma_desc_write(chan, XILINX_VDMA_REG_START_ADDRESS(i++), segment->hw.buf_addr); - last = segment; - } - - if (!last) - return; + last = segment; + } - /* HW expects these parameters to be same for one transaction */ - vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize); - vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE, - last->hw.stride); - vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize); + if (!last) + return; - chan->desc_submitcount++; - chan->desc_pendingcount--; - list_del(&desc->node); - list_add_tail(&desc->node, &chan->active_list); - if (chan->desc_submitcount == chan->num_frms) - chan->desc_submitcount = 0; - } + /* HW expects these parameters to be same for one transaction */ + vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize); + vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE, + last->hw.stride); + vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize); + + chan->desc_submitcount++; + chan->desc_pendingcount--; + list_del(&desc->node); + list_add_tail(&desc->node, &chan->active_list); + if (chan->desc_submitcount == chan->num_frms) + chan->desc_submitcount = 0; chan->idle = false; } -- cgit v1.2.3 From 21b9e979501fdb5f6797193d70428a2b00bd5247 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 19 Jul 2017 14:55:26 -0700 Subject: device-dax: Kill dax_region ida Commit bbb3be170ac2 "device-dax: fix sysfs duplicate warnings" arranged for passing a dax instance-id to devm_create_dax_dev(), rather than generating one internally. Remove the dax_region ida and related code. Signed-off-by: Dan Williams --- drivers/dax/dax-private.h | 3 --- drivers/dax/device.c | 24 +++--------------------- 2 files changed, 3 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index b6fc4f04636d..d1b36a42132f 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -28,7 +28,6 @@ */ struct dax_region { int id; - struct ida ida; void *base; struct kref kref; struct device *dev; @@ -42,7 +41,6 @@ struct dax_region { * @region - parent region * @dax_dev - core dax functionality * @dev - device core - * @id - child id in the region * @num_resources - number of physical address extents in this device * @res - array of physical address ranges */ @@ -50,7 +48,6 @@ struct dev_dax { struct dax_region *region; struct dax_device *dax_dev; struct device dev; - int id; int num_resources; struct resource res[0]; }; diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 948806e57cee..a5a670c1cd58 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -128,7 +128,6 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, dax_region->pfn_flags = pfn_flags; kref_init(&dax_region->kref); dax_region->id = region_id; - ida_init(&dax_region->ida); dax_region->align = align; dax_region->dev = parent; dax_region->base = addr; @@ -582,8 +581,6 @@ static void dev_dax_release(struct device *dev) struct dax_region *dax_region = dev_dax->region; struct dax_device *dax_dev = dev_dax->dax_dev; - if (dev_dax->id >= 0) - ida_simple_remove(&dax_region->ida, dev_dax->id); dax_region_put(dax_region); put_dax(dax_dev); kfree(dev_dax); @@ -642,19 +639,7 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, } if (i < count) - goto err_id; - - if (id < 0) { - id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); - dev_dax->id = id; - if (id < 0) { - rc = id; - goto err_id; - } - } else { - /* region provider owns @id lifetime */ - dev_dax->id = -1; - } + goto err; /* * No 'host' or dax_operations since there is no access to this @@ -663,7 +648,7 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, dax_dev = alloc_dax(dev_dax, NULL, NULL); if (!dax_dev) { rc = -ENOMEM; - goto err_dax; + goto err; } /* from here on we're committed to teardown via dax_dev_release() */ @@ -700,10 +685,7 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, return dev_dax; - err_dax: - if (dev_dax->id >= 0) - ida_simple_remove(&dax_region->ida, dev_dax->id); - err_id: + err: kfree(dev_dax); return ERR_PTR(rc); -- cgit v1.2.3 From 93694f9630b0ed29cda61df58e480dcb34ef52fd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 19 Jul 2017 15:57:44 -0700 Subject: device-dax: Kill dax_region base Nothing consumes this attribute of a region and devres otherwise remembers the value for de-allocation purposes. Signed-off-by: Dan Williams --- drivers/dax/dax-private.h | 2 -- drivers/dax/device-dax.h | 5 ++--- drivers/dax/device.c | 3 +-- drivers/dax/pmem.c | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index d1b36a42132f..9b393c218fe4 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -19,7 +19,6 @@ /** * struct dax_region - mapping infrastructure for dax devices * @id: kernel-wide unique region for a memory range - * @base: linear address corresponding to @res * @kref: to pin while other agents have a need to do lookups * @dev: parent device backing this region * @align: allocation and mapping alignment for child dax devices @@ -28,7 +27,6 @@ */ struct dax_region { int id; - void *base; struct kref kref; struct device *dev; unsigned int align; diff --git a/drivers/dax/device-dax.h b/drivers/dax/device-dax.h index 688b051750bd..4f1c69e1b3a2 100644 --- a/drivers/dax/device-dax.h +++ b/drivers/dax/device-dax.h @@ -17,9 +17,8 @@ struct dev_dax; struct resource; struct dax_region; void dax_region_put(struct dax_region *dax_region); -struct dax_region *alloc_dax_region(struct device *parent, - int region_id, struct resource *res, unsigned int align, - void *addr, unsigned long flags); +struct dax_region *alloc_dax_region(struct device *parent, int region_id, + struct resource *res, unsigned int align, unsigned long flags); struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, struct resource *res, int count); #endif /* __DEVICE_DAX_H__ */ diff --git a/drivers/dax/device.c b/drivers/dax/device.c index a5a670c1cd58..811c1015194c 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -100,7 +100,7 @@ static void dax_region_unregister(void *region) } struct dax_region *alloc_dax_region(struct device *parent, int region_id, - struct resource *res, unsigned int align, void *addr, + struct resource *res, unsigned int align, unsigned long pfn_flags) { struct dax_region *dax_region; @@ -130,7 +130,6 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, dax_region->id = region_id; dax_region->align = align; dax_region->dev = parent; - dax_region->base = addr; if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) { kfree(dax_region); return NULL; diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 2c1f459c0c63..72a76105eb02 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -125,7 +125,7 @@ static int dax_pmem_probe(struct device *dev) return -EINVAL; dax_region = alloc_dax_region(dev, region_id, &res, - le32_to_cpu(pfn_sb->align), addr, PFN_DEV|PFN_MAP); + le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP); if (!dax_region) return -ENOMEM; -- cgit v1.2.3 From 753a0850e707e9a8c5861356222f9b9e4eba7945 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 14 Jul 2017 13:54:50 -0700 Subject: device-dax: Remove multi-resource infrastructure The multi-resource implementation anticipated discontiguous sub-division support. That has not yet materialized, delete the infrastructure and related code. Signed-off-by: Dan Williams --- drivers/dax/dax-private.h | 4 ---- drivers/dax/device-dax.h | 3 +-- drivers/dax/device.c | 49 ++++++++--------------------------------------- drivers/dax/pmem.c | 3 +-- 4 files changed, 10 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index 9b393c218fe4..dbd077653b5c 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -39,14 +39,10 @@ struct dax_region { * @region - parent region * @dax_dev - core dax functionality * @dev - device core - * @num_resources - number of physical address extents in this device - * @res - array of physical address ranges */ struct dev_dax { struct dax_region *region; struct dax_device *dax_dev; struct device dev; - int num_resources; - struct resource res[0]; }; #endif diff --git a/drivers/dax/device-dax.h b/drivers/dax/device-dax.h index 4f1c69e1b3a2..e9be99584b92 100644 --- a/drivers/dax/device-dax.h +++ b/drivers/dax/device-dax.h @@ -19,6 +19,5 @@ struct dax_region; void dax_region_put(struct dax_region *dax_region); struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, unsigned long flags); -struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, - int id, struct resource *res, int count); +struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id); #endif /* __DEVICE_DAX_H__ */ diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 811c1015194c..db12e24b8005 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -151,11 +151,7 @@ static ssize_t size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dev_dax *dev_dax = to_dev_dax(dev); - unsigned long long size = 0; - int i; - - for (i = 0; i < dev_dax->num_resources; i++) - size += resource_size(&dev_dax->res[i]); + unsigned long long size = resource_size(&dev_dax->region->res); return sprintf(buf, "%llu\n", size); } @@ -224,21 +220,11 @@ static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, __weak phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff, unsigned long size) { - struct resource *res; - /* gcc-4.6.3-nolibc for i386 complains that this is uninitialized */ - phys_addr_t uninitialized_var(phys); - int i; - - for (i = 0; i < dev_dax->num_resources; i++) { - res = &dev_dax->res[i]; - phys = pgoff * PAGE_SIZE + res->start; - if (phys >= res->start && phys <= res->end) - break; - pgoff -= PHYS_PFN(resource_size(res)); - } + struct resource *res = &dev_dax->region->res; + phys_addr_t phys; - if (i < dev_dax->num_resources) { - res = &dev_dax->res[i]; + phys = pgoff * PAGE_SIZE + res->start; + if (phys >= res->start && phys <= res->end) { if (phys + size - 1 <= res->end) return phys; } @@ -608,8 +594,7 @@ static void unregister_dev_dax(void *dev) put_device(dev); } -struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, - int id, struct resource *res, int count) +struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id) { struct device *parent = dax_region->dev; struct dax_device *dax_dev; @@ -617,29 +602,12 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, struct inode *inode; struct device *dev; struct cdev *cdev; - int rc, i; + int rc; - if (!count) - return ERR_PTR(-EINVAL); - - dev_dax = kzalloc(struct_size(dev_dax, res, count), GFP_KERNEL); + dev_dax = kzalloc(sizeof(*dev_dax), GFP_KERNEL); if (!dev_dax) return ERR_PTR(-ENOMEM); - for (i = 0; i < count; i++) { - if (!IS_ALIGNED(res[i].start, dax_region->align) - || !IS_ALIGNED(resource_size(&res[i]), - dax_region->align)) { - rc = -EINVAL; - break; - } - dev_dax->res[i].start = res[i].start; - dev_dax->res[i].end = res[i].end; - } - - if (i < count) - goto err; - /* * No 'host' or dax_operations since there is no access to this * device outside of mmap of the resulting character device. @@ -659,7 +627,6 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, cdev_init(cdev, &dax_fops); cdev->owner = parent->driver->owner; - dev_dax->num_resources = count; dev_dax->dax_dev = dax_dev; dev_dax->region = dax_region; kref_get(&dax_region->kref); diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 72a76105eb02..6c61a019f997 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -129,8 +129,7 @@ static int dax_pmem_probe(struct device *dev) if (!dax_region) return -ENOMEM; - /* TODO: support for subdividing a dax region... */ - dev_dax = devm_create_dev_dax(dax_region, id, &res, 1); + dev_dax = devm_create_dev_dax(dax_region, id); /* child dev_dax instances now own the lifetime of the dax_region */ dax_region_put(dax_region); -- cgit v1.2.3 From 51cf784c42d07fbd62cb604836a9270cf3361509 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 12 Jul 2017 17:58:21 -0700 Subject: device-dax: Start defining a dax bus model Towards eliminating the dax_class, move the dax-device-attribute enabling to a new bus.c file in the core. The amount of code thrash of sub-sequent patches is reduced as no logic changes are made, just pure code movement. A temporary export of unregister_dex_dax() and dax_attribute_groups is needed to preserve compilation, but those symbols become static again in a follow-on patch. Signed-off-by: Dan Williams --- drivers/dax/Makefile | 1 + drivers/dax/bus.c | 174 +++++++++++++++++++++++++++++++++++++++++++ drivers/dax/bus.h | 15 ++++ drivers/dax/dax-private.h | 14 ++++ drivers/dax/dax.h | 18 ----- drivers/dax/device-dax.h | 23 ------ drivers/dax/device.c | 185 +--------------------------------------------- drivers/dax/pmem.c | 2 +- drivers/dax/super.c | 1 + 9 files changed, 209 insertions(+), 224 deletions(-) create mode 100644 drivers/dax/bus.c create mode 100644 drivers/dax/bus.h delete mode 100644 drivers/dax/dax.h delete mode 100644 drivers/dax/device-dax.h (limited to 'drivers') diff --git a/drivers/dax/Makefile b/drivers/dax/Makefile index 574286fac87c..658e6b9b1d74 100644 --- a/drivers/dax/Makefile +++ b/drivers/dax/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_DEV_DAX) += device_dax.o obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o dax-y := super.o +dax-y += bus.o dax_pmem-y := pmem.o device_dax-y := device.o diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c new file mode 100644 index 000000000000..8a398e8e1956 --- /dev/null +++ b/drivers/dax/bus.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */ +#include +#include +#include +#include "dax-private.h" +#include "bus.h" + +/* + * Rely on the fact that drvdata is set before the attributes are + * registered, and that the attributes are unregistered before drvdata + * is cleared to assume that drvdata is always valid. + */ +static ssize_t id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dax_region *dax_region = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", dax_region->id); +} +static DEVICE_ATTR_RO(id); + +static ssize_t region_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dax_region *dax_region = dev_get_drvdata(dev); + + return sprintf(buf, "%llu\n", (unsigned long long) + resource_size(&dax_region->res)); +} +static struct device_attribute dev_attr_region_size = __ATTR(size, 0444, + region_size_show, NULL); + +static ssize_t align_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dax_region *dax_region = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", dax_region->align); +} +static DEVICE_ATTR_RO(align); + +static struct attribute *dax_region_attributes[] = { + &dev_attr_region_size.attr, + &dev_attr_align.attr, + &dev_attr_id.attr, + NULL, +}; + +static const struct attribute_group dax_region_attribute_group = { + .name = "dax_region", + .attrs = dax_region_attributes, +}; + +static const struct attribute_group *dax_region_attribute_groups[] = { + &dax_region_attribute_group, + NULL, +}; + +static void dax_region_free(struct kref *kref) +{ + struct dax_region *dax_region; + + dax_region = container_of(kref, struct dax_region, kref); + kfree(dax_region); +} + +void dax_region_put(struct dax_region *dax_region) +{ + kref_put(&dax_region->kref, dax_region_free); +} +EXPORT_SYMBOL_GPL(dax_region_put); + +static void dax_region_unregister(void *region) +{ + struct dax_region *dax_region = region; + + sysfs_remove_groups(&dax_region->dev->kobj, + dax_region_attribute_groups); + dax_region_put(dax_region); +} + +struct dax_region *alloc_dax_region(struct device *parent, int region_id, + struct resource *res, unsigned int align, + unsigned long pfn_flags) +{ + struct dax_region *dax_region; + + /* + * The DAX core assumes that it can store its private data in + * parent->driver_data. This WARN is a reminder / safeguard for + * developers of device-dax drivers. + */ + if (dev_get_drvdata(parent)) { + dev_WARN(parent, "dax core failed to setup private data\n"); + return NULL; + } + + if (!IS_ALIGNED(res->start, align) + || !IS_ALIGNED(resource_size(res), align)) + return NULL; + + dax_region = kzalloc(sizeof(*dax_region), GFP_KERNEL); + if (!dax_region) + return NULL; + + dev_set_drvdata(parent, dax_region); + memcpy(&dax_region->res, res, sizeof(*res)); + dax_region->pfn_flags = pfn_flags; + kref_init(&dax_region->kref); + dax_region->id = region_id; + dax_region->align = align; + dax_region->dev = parent; + if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) { + kfree(dax_region); + return NULL; + } + + kref_get(&dax_region->kref); + if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region)) + return NULL; + return dax_region; +} +EXPORT_SYMBOL_GPL(alloc_dax_region); + +static ssize_t size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dev_dax *dev_dax = to_dev_dax(dev); + unsigned long long size = resource_size(&dev_dax->region->res); + + return sprintf(buf, "%llu\n", size); +} +static DEVICE_ATTR_RO(size); + +static struct attribute *dev_dax_attributes[] = { + &dev_attr_size.attr, + NULL, +}; + +static const struct attribute_group dev_dax_attribute_group = { + .attrs = dev_dax_attributes, +}; + +const struct attribute_group *dax_attribute_groups[] = { + &dev_dax_attribute_group, + NULL, +}; +EXPORT_SYMBOL_GPL(dax_attribute_groups); + +void kill_dev_dax(struct dev_dax *dev_dax) +{ + struct dax_device *dax_dev = dev_dax->dax_dev; + struct inode *inode = dax_inode(dax_dev); + + kill_dax(dax_dev); + unmap_mapping_range(inode->i_mapping, 0, 0, 1); +} +EXPORT_SYMBOL_GPL(kill_dev_dax); + +void unregister_dev_dax(void *dev) +{ + struct dev_dax *dev_dax = to_dev_dax(dev); + struct dax_device *dax_dev = dev_dax->dax_dev; + struct inode *inode = dax_inode(dax_dev); + struct cdev *cdev = inode->i_cdev; + + dev_dbg(dev, "trace\n"); + + kill_dev_dax(dev_dax); + cdev_device_del(cdev, dev); + put_device(dev); +} +EXPORT_SYMBOL_GPL(unregister_dev_dax); diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h new file mode 100644 index 000000000000..840865aa69e8 --- /dev/null +++ b/drivers/dax/bus.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ +#ifndef __DAX_BUS_H__ +#define __DAX_BUS_H__ +struct device; +struct dev_dax; +struct resource; +struct dax_device; +struct dax_region; +void dax_region_put(struct dax_region *dax_region); +struct dax_region *alloc_dax_region(struct device *parent, int region_id, + struct resource *res, unsigned int align, unsigned long flags); +struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id); +void kill_dev_dax(struct dev_dax *dev_dax); +#endif /* __DAX_BUS_H__ */ diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index dbd077653b5c..620c3f4eefe7 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -16,6 +16,15 @@ #include #include +/* private routines between core files */ +struct dax_device; +struct dax_device *inode_dax(struct inode *inode); +struct inode *dax_inode(struct dax_device *dax_dev); + +/* temporary until devm_create_dax_dev moves to bus.c */ +extern const struct attribute_group *dax_attribute_groups[]; +void unregister_dev_dax(void *dev); + /** * struct dax_region - mapping infrastructure for dax devices * @id: kernel-wide unique region for a memory range @@ -45,4 +54,9 @@ struct dev_dax { struct dax_device *dax_dev; struct device dev; }; + +static inline struct dev_dax *to_dev_dax(struct device *dev) +{ + return container_of(dev, struct dev_dax, dev); +} #endif diff --git a/drivers/dax/dax.h b/drivers/dax/dax.h deleted file mode 100644 index f9e5feea742c..000000000000 --- a/drivers/dax/dax.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright(c) 2016 - 2017 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __DAX_H__ -#define __DAX_H__ -struct dax_device; -struct dax_device *inode_dax(struct inode *inode); -struct inode *dax_inode(struct dax_device *dax_dev); -#endif /* __DAX_H__ */ diff --git a/drivers/dax/device-dax.h b/drivers/dax/device-dax.h deleted file mode 100644 index e9be99584b92..000000000000 --- a/drivers/dax/device-dax.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __DEVICE_DAX_H__ -#define __DEVICE_DAX_H__ -struct device; -struct dev_dax; -struct resource; -struct dax_region; -void dax_region_put(struct dax_region *dax_region); -struct dax_region *alloc_dax_region(struct device *parent, int region_id, - struct resource *res, unsigned int align, unsigned long flags); -struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id); -#endif /* __DEVICE_DAX_H__ */ diff --git a/drivers/dax/device.c b/drivers/dax/device.c index db12e24b8005..1fc375783e0b 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -1,15 +1,5 @@ -/* - * Copyright(c) 2016 - 2017 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2016-2018 Intel Corporation. All rights reserved. */ #include #include #include @@ -21,156 +11,10 @@ #include #include #include "dax-private.h" -#include "dax.h" +#include "bus.h" static struct class *dax_class; -/* - * Rely on the fact that drvdata is set before the attributes are - * registered, and that the attributes are unregistered before drvdata - * is cleared to assume that drvdata is always valid. - */ -static ssize_t id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dax_region *dax_region = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", dax_region->id); -} -static DEVICE_ATTR_RO(id); - -static ssize_t region_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dax_region *dax_region = dev_get_drvdata(dev); - - return sprintf(buf, "%llu\n", (unsigned long long) - resource_size(&dax_region->res)); -} -static struct device_attribute dev_attr_region_size = __ATTR(size, 0444, - region_size_show, NULL); - -static ssize_t align_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dax_region *dax_region = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", dax_region->align); -} -static DEVICE_ATTR_RO(align); - -static struct attribute *dax_region_attributes[] = { - &dev_attr_region_size.attr, - &dev_attr_align.attr, - &dev_attr_id.attr, - NULL, -}; - -static const struct attribute_group dax_region_attribute_group = { - .name = "dax_region", - .attrs = dax_region_attributes, -}; - -static const struct attribute_group *dax_region_attribute_groups[] = { - &dax_region_attribute_group, - NULL, -}; - -static void dax_region_free(struct kref *kref) -{ - struct dax_region *dax_region; - - dax_region = container_of(kref, struct dax_region, kref); - kfree(dax_region); -} - -void dax_region_put(struct dax_region *dax_region) -{ - kref_put(&dax_region->kref, dax_region_free); -} -EXPORT_SYMBOL_GPL(dax_region_put); - -static void dax_region_unregister(void *region) -{ - struct dax_region *dax_region = region; - - sysfs_remove_groups(&dax_region->dev->kobj, - dax_region_attribute_groups); - dax_region_put(dax_region); -} - -struct dax_region *alloc_dax_region(struct device *parent, int region_id, - struct resource *res, unsigned int align, - unsigned long pfn_flags) -{ - struct dax_region *dax_region; - - /* - * The DAX core assumes that it can store its private data in - * parent->driver_data. This WARN is a reminder / safeguard for - * developers of device-dax drivers. - */ - if (dev_get_drvdata(parent)) { - dev_WARN(parent, "dax core failed to setup private data\n"); - return NULL; - } - - if (!IS_ALIGNED(res->start, align) - || !IS_ALIGNED(resource_size(res), align)) - return NULL; - - dax_region = kzalloc(sizeof(*dax_region), GFP_KERNEL); - if (!dax_region) - return NULL; - - dev_set_drvdata(parent, dax_region); - memcpy(&dax_region->res, res, sizeof(*res)); - dax_region->pfn_flags = pfn_flags; - kref_init(&dax_region->kref); - dax_region->id = region_id; - dax_region->align = align; - dax_region->dev = parent; - if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) { - kfree(dax_region); - return NULL; - } - - kref_get(&dax_region->kref); - if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region)) - return NULL; - return dax_region; -} -EXPORT_SYMBOL_GPL(alloc_dax_region); - -static struct dev_dax *to_dev_dax(struct device *dev) -{ - return container_of(dev, struct dev_dax, dev); -} - -static ssize_t size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dev_dax *dev_dax = to_dev_dax(dev); - unsigned long long size = resource_size(&dev_dax->region->res); - - return sprintf(buf, "%llu\n", size); -} -static DEVICE_ATTR_RO(size); - -static struct attribute *dev_dax_attributes[] = { - &dev_attr_size.attr, - NULL, -}; - -static const struct attribute_group dev_dax_attribute_group = { - .attrs = dev_dax_attributes, -}; - -static const struct attribute_group *dax_attribute_groups[] = { - &dev_dax_attribute_group, - NULL, -}; - static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, const char *func) { @@ -571,29 +415,6 @@ static void dev_dax_release(struct device *dev) kfree(dev_dax); } -static void kill_dev_dax(struct dev_dax *dev_dax) -{ - struct dax_device *dax_dev = dev_dax->dax_dev; - struct inode *inode = dax_inode(dax_dev); - - kill_dax(dax_dev); - unmap_mapping_range(inode->i_mapping, 0, 0, 1); -} - -static void unregister_dev_dax(void *dev) -{ - struct dev_dax *dev_dax = to_dev_dax(dev); - struct dax_device *dax_dev = dev_dax->dax_dev; - struct inode *inode = dax_inode(dax_dev); - struct cdev *cdev = inode->i_cdev; - - dev_dbg(dev, "trace\n"); - - kill_dev_dax(dev_dax); - cdev_device_del(cdev, dev); - put_device(dev); -} - struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id) { struct device *parent = dax_region->dev; diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 6c61a019f997..e1b50d8fd1f8 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -16,7 +16,7 @@ #include #include "../nvdimm/pfn.h" #include "../nvdimm/nd.h" -#include "device-dax.h" +#include "bus.h" struct dax_pmem { struct device *dev; diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 6e928f37d084..0ecc1a2cf1cc 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -22,6 +22,7 @@ #include #include #include +#include "dax-private.h" static dev_t dax_devt; DEFINE_STATIC_SRCU(dax_srcu); -- cgit v1.2.3 From 9567da0b408a2553d32ca83cba4f1fc5a8aad459 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 12 Jul 2017 17:58:21 -0700 Subject: device-dax: Introduce bus + driver model In support of multiple device-dax instances per device-dax-region and allowing the 'kmem' driver to attach to dax-instances instead of the current device-node access, convert the dax sub-system from a class to a bus. Recall that the kmem driver takes reserved / special purpose memories and assigns them to be managed by the core-mm. Aside from the fact the device-dax instances are registered and probed on a bus, two other lifetime-management changes are made: 1/ Delay attaching a cdev until driver probe time 2/ A new run_dax() helper is introduced to allow restoring dax-operation after a kill_dax() event. So, at driver ->probe() time we run_dax() and at ->remove() time we kill_dax() and invalidate all mappings. Signed-off-by: Dan Williams --- drivers/dax/bus.c | 133 +++++++++++++++++++++++++++++++++++++++++++--- drivers/dax/bus.h | 16 ++++++ drivers/dax/dax-private.h | 6 +-- drivers/dax/device.c | 95 +++++++++++---------------------- drivers/dax/super.c | 40 +++++++++----- 5 files changed, 203 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 8a398e8e1956..0cff32102c4c 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -6,6 +6,33 @@ #include "dax-private.h" #include "bus.h" +static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + /* + * We only ever expect to handle device-dax instances, i.e. the + * @type argument to MODULE_ALIAS_DAX_DEVICE() is always zero + */ + return add_uevent_var(env, "MODALIAS=" DAX_DEVICE_MODALIAS_FMT, 0); +} + +static int dax_bus_match(struct device *dev, struct device_driver *drv); + +static struct bus_type dax_bus_type = { + .name = "dax", + .uevent = dax_bus_uevent, + .match = dax_bus_match, +}; + +static int dax_bus_match(struct device *dev, struct device_driver *drv) +{ + /* + * The drivers that can register on the 'dax' bus are private to + * drivers/dax/ so any device and driver on the bus always + * match. + */ + return 1; +} + /* * Rely on the fact that drvdata is set before the attributes are * registered, and that the attributes are unregistered before drvdata @@ -142,11 +169,10 @@ static const struct attribute_group dev_dax_attribute_group = { .attrs = dev_dax_attributes, }; -const struct attribute_group *dax_attribute_groups[] = { +static const struct attribute_group *dax_attribute_groups[] = { &dev_dax_attribute_group, NULL, }; -EXPORT_SYMBOL_GPL(dax_attribute_groups); void kill_dev_dax(struct dev_dax *dev_dax) { @@ -158,17 +184,108 @@ void kill_dev_dax(struct dev_dax *dev_dax) } EXPORT_SYMBOL_GPL(kill_dev_dax); -void unregister_dev_dax(void *dev) +static void dev_dax_release(struct device *dev) { struct dev_dax *dev_dax = to_dev_dax(dev); + struct dax_region *dax_region = dev_dax->region; struct dax_device *dax_dev = dev_dax->dax_dev; - struct inode *inode = dax_inode(dax_dev); - struct cdev *cdev = inode->i_cdev; - dev_dbg(dev, "trace\n"); + dax_region_put(dax_region); + put_dax(dax_dev); + kfree(dev_dax); +} + +static void unregister_dev_dax(void *dev) +{ + struct dev_dax *dev_dax = to_dev_dax(dev); + + dev_dbg(dev, "%s\n", __func__); kill_dev_dax(dev_dax); - cdev_device_del(cdev, dev); + device_del(dev); put_device(dev); } -EXPORT_SYMBOL_GPL(unregister_dev_dax); + +struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id) +{ + struct device *parent = dax_region->dev; + struct dax_device *dax_dev; + struct dev_dax *dev_dax; + struct inode *inode; + struct device *dev; + int rc = -ENOMEM; + + if (id < 0) + return ERR_PTR(-EINVAL); + + dev_dax = kzalloc(sizeof(*dev_dax), GFP_KERNEL); + if (!dev_dax) + return ERR_PTR(-ENOMEM); + + /* + * No 'host' or dax_operations since there is no access to this + * device outside of mmap of the resulting character device. + */ + dax_dev = alloc_dax(dev_dax, NULL, NULL); + if (!dax_dev) + goto err; + + /* a device_dax instance is dead while the driver is not attached */ + kill_dax(dax_dev); + + /* from here on we're committed to teardown via dax_dev_release() */ + dev = &dev_dax->dev; + device_initialize(dev); + + dev_dax->dax_dev = dax_dev; + dev_dax->region = dax_region; + kref_get(&dax_region->kref); + + inode = dax_inode(dax_dev); + dev->devt = inode->i_rdev; + dev->bus = &dax_bus_type; + dev->parent = parent; + dev->groups = dax_attribute_groups; + dev->release = dev_dax_release; + dev_set_name(dev, "dax%d.%d", dax_region->id, id); + + rc = device_add(dev); + if (rc) { + kill_dev_dax(dev_dax); + put_device(dev); + return ERR_PTR(rc); + } + + rc = devm_add_action_or_reset(dax_region->dev, unregister_dev_dax, dev); + if (rc) + return ERR_PTR(rc); + + return dev_dax; + + err: + kfree(dev_dax); + + return ERR_PTR(rc); +} +EXPORT_SYMBOL_GPL(devm_create_dev_dax); + +int __dax_driver_register(struct device_driver *drv, + struct module *module, const char *mod_name) +{ + drv->owner = module; + drv->name = mod_name; + drv->mod_name = mod_name; + drv->bus = &dax_bus_type; + return driver_register(drv); +} +EXPORT_SYMBOL_GPL(__dax_driver_register); + +int __init dax_bus_init(void) +{ + return bus_register(&dax_bus_type); +} + +void __exit dax_bus_exit(void) +{ + bus_unregister(&dax_bus_type); +} diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index 840865aa69e8..ea509504df3a 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -11,5 +11,21 @@ void dax_region_put(struct dax_region *dax_region); struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, unsigned long flags); struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id); +int __dax_driver_register(struct device_driver *drv, + struct module *module, const char *mod_name); +#define dax_driver_register(driver) \ + __dax_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) void kill_dev_dax(struct dev_dax *dev_dax); + +/* + * While run_dax() is potentially a generic operation that could be + * defined in include/linux/dax.h we don't want to grow any users + * outside of drivers/dax/ + */ +void run_dax(struct dax_device *dax_dev); + +#define MODULE_ALIAS_DAX_DEVICE(type) \ + MODULE_ALIAS("dax:t" __stringify(type) "*") +#define DAX_DEVICE_MODALIAS_FMT "dax:t%d" + #endif /* __DAX_BUS_H__ */ diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index 620c3f4eefe7..c3a121700837 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -20,10 +20,8 @@ struct dax_device; struct dax_device *inode_dax(struct inode *inode); struct inode *dax_inode(struct dax_device *dax_dev); - -/* temporary until devm_create_dax_dev moves to bus.c */ -extern const struct attribute_group *dax_attribute_groups[]; -void unregister_dev_dax(void *dev); +int dax_bus_init(void); +void dax_bus_exit(void); /** * struct dax_region - mapping infrastructure for dax devices diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 1fc375783e0b..f55829404a24 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -13,8 +13,6 @@ #include "dax-private.h" #include "bus.h" -static struct class *dax_class; - static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, const char *func) { @@ -404,93 +402,64 @@ static const struct file_operations dax_fops = { .mmap_supported_flags = MAP_SYNC, }; -static void dev_dax_release(struct device *dev) +static void dev_dax_cdev_del(void *cdev) { - struct dev_dax *dev_dax = to_dev_dax(dev); - struct dax_region *dax_region = dev_dax->region; - struct dax_device *dax_dev = dev_dax->dax_dev; + cdev_del(cdev); +} - dax_region_put(dax_region); - put_dax(dax_dev); - kfree(dev_dax); +static void dev_dax_kill(void *dev_dax) +{ + kill_dev_dax(dev_dax); } -struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id) +static int dev_dax_probe(struct device *dev) { - struct device *parent = dax_region->dev; - struct dax_device *dax_dev; - struct dev_dax *dev_dax; + struct dev_dax *dev_dax = to_dev_dax(dev); + struct dax_device *dax_dev = dev_dax->dax_dev; struct inode *inode; - struct device *dev; struct cdev *cdev; int rc; - dev_dax = kzalloc(sizeof(*dev_dax), GFP_KERNEL); - if (!dev_dax) - return ERR_PTR(-ENOMEM); - - /* - * No 'host' or dax_operations since there is no access to this - * device outside of mmap of the resulting character device. - */ - dax_dev = alloc_dax(dev_dax, NULL, NULL); - if (!dax_dev) { - rc = -ENOMEM; - goto err; - } - - /* from here on we're committed to teardown via dax_dev_release() */ - dev = &dev_dax->dev; - device_initialize(dev); - inode = dax_inode(dax_dev); cdev = inode->i_cdev; cdev_init(cdev, &dax_fops); - cdev->owner = parent->driver->owner; - - dev_dax->dax_dev = dax_dev; - dev_dax->region = dax_region; - kref_get(&dax_region->kref); - - dev->devt = inode->i_rdev; - dev->class = dax_class; - dev->parent = parent; - dev->groups = dax_attribute_groups; - dev->release = dev_dax_release; - dev_set_name(dev, "dax%d.%d", dax_region->id, id); - - rc = cdev_device_add(cdev, dev); - if (rc) { - kill_dev_dax(dev_dax); - put_device(dev); - return ERR_PTR(rc); - } - - rc = devm_add_action_or_reset(dax_region->dev, unregister_dev_dax, dev); + cdev->owner = dev->driver->owner; + cdev_set_parent(cdev, &dev->kobj); + rc = cdev_add(cdev, dev->devt, 1); if (rc) - return ERR_PTR(rc); + return rc; - return dev_dax; + rc = devm_add_action_or_reset(dev, dev_dax_cdev_del, cdev); + if (rc) + return rc; - err: - kfree(dev_dax); + run_dax(dax_dev); + return devm_add_action_or_reset(dev, dev_dax_kill, dev_dax); +} - return ERR_PTR(rc); +static int dev_dax_remove(struct device *dev) +{ + /* all probe actions are unwound by devm */ + return 0; } -EXPORT_SYMBOL_GPL(devm_create_dev_dax); + +static struct device_driver device_dax_driver = { + .probe = dev_dax_probe, + .remove = dev_dax_remove, +}; static int __init dax_init(void) { - dax_class = class_create(THIS_MODULE, "dax"); - return PTR_ERR_OR_ZERO(dax_class); + return dax_driver_register(&device_dax_driver); } static void __exit dax_exit(void) { - class_destroy(dax_class); + driver_unregister(&device_dax_driver); } MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL v2"); -subsys_initcall(dax_init); +module_init(dax_init); module_exit(dax_exit); +MODULE_ALIAS_DAX_DEVICE(0); diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 0ecc1a2cf1cc..ccb22d8db3a2 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -366,11 +366,15 @@ void kill_dax(struct dax_device *dax_dev) spin_lock(&dax_host_lock); hlist_del_init(&dax_dev->list); spin_unlock(&dax_host_lock); - - dax_dev->private = NULL; } EXPORT_SYMBOL_GPL(kill_dax); +void run_dax(struct dax_device *dax_dev) +{ + set_bit(DAXDEV_ALIVE, &dax_dev->flags); +} +EXPORT_SYMBOL_GPL(run_dax); + static struct inode *dax_alloc_inode(struct super_block *sb) { struct dax_device *dax_dev; @@ -585,6 +589,8 @@ EXPORT_SYMBOL_GPL(dax_inode); void *dax_get_private(struct dax_device *dax_dev) { + if (!test_bit(DAXDEV_ALIVE, &dax_dev->flags)) + return NULL; return dax_dev->private; } EXPORT_SYMBOL_GPL(dax_get_private); @@ -598,7 +604,7 @@ static void init_once(void *_dax_dev) inode_init_once(inode); } -static int __dax_fs_init(void) +static int dax_fs_init(void) { int rc; @@ -630,35 +636,45 @@ static int __dax_fs_init(void) return rc; } -static void __dax_fs_exit(void) +static void dax_fs_exit(void) { kern_unmount(dax_mnt); unregister_filesystem(&dax_fs_type); kmem_cache_destroy(dax_cache); } -static int __init dax_fs_init(void) +static int __init dax_core_init(void) { int rc; - rc = __dax_fs_init(); + rc = dax_fs_init(); if (rc) return rc; rc = alloc_chrdev_region(&dax_devt, 0, MINORMASK+1, "dax"); if (rc) - __dax_fs_exit(); - return rc; + goto err_chrdev; + + rc = dax_bus_init(); + if (rc) + goto err_bus; + return 0; + +err_bus: + unregister_chrdev_region(dax_devt, MINORMASK+1); +err_chrdev: + dax_fs_exit(); + return 0; } -static void __exit dax_fs_exit(void) +static void __exit dax_core_exit(void) { unregister_chrdev_region(dax_devt, MINORMASK+1); ida_destroy(&dax_minor_ida); - __dax_fs_exit(); + dax_fs_exit(); } MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL v2"); -subsys_initcall(dax_fs_init); -module_exit(dax_fs_exit); +subsys_initcall(dax_core_init); +module_exit(dax_core_exit); -- cgit v1.2.3 From 89ec9f2cfa36cc5fca2fb445ed221bb9add7b536 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Oct 2018 15:52:42 -0700 Subject: device-dax: Move resource pinning+mapping into the common driver Move the responsibility of calling devm_request_resource() and devm_memremap_pages() into the common device-dax driver. This is another preparatory step to allowing an alternate personality driver for a device-dax range. Signed-off-by: Dan Williams --- drivers/dax/bus.c | 6 +++- drivers/dax/bus.h | 3 +- drivers/dax/dax-private.h | 9 ++++- drivers/dax/device.c | 61 ++++++++++++++++++++++++++++++++ drivers/dax/pmem.c | 90 ++++++++--------------------------------------- 5 files changed, 90 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 0cff32102c4c..69aae2cbd45f 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */ +#include #include #include #include @@ -206,7 +207,8 @@ static void unregister_dev_dax(void *dev) put_device(dev); } -struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id) +struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, + struct dev_pagemap *pgmap) { struct device *parent = dax_region->dev; struct dax_device *dax_dev; @@ -222,6 +224,8 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id) if (!dev_dax) return ERR_PTR(-ENOMEM); + memcpy(&dev_dax->pgmap, pgmap, sizeof(*pgmap)); + /* * No 'host' or dax_operations since there is no access to this * device outside of mmap of the resulting character device. diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index ea509504df3a..e08e0c394983 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -10,7 +10,8 @@ struct dax_region; void dax_region_put(struct dax_region *dax_region); struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, unsigned long flags); -struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id); +struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, + struct dev_pagemap *pgmap); int __dax_driver_register(struct device_driver *drv, struct module *module, const char *mod_name); #define dax_driver_register(driver) \ diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index c3a121700837..a82ce48f5884 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -42,15 +42,22 @@ struct dax_region { }; /** - * struct dev_dax - instance data for a subdivision of a dax region + * struct dev_dax - instance data for a subdivision of a dax region, and + * data while the device is activated in the driver. * @region - parent region * @dax_dev - core dax functionality * @dev - device core + * @pgmap - pgmap for memmap setup / lifetime (driver owned) + * @ref: pgmap reference count (driver owned) + * @cmp: @ref final put completion (driver owned) */ struct dev_dax { struct dax_region *region; struct dax_device *dax_dev; struct device dev; + struct dev_pagemap pgmap; + struct percpu_ref ref; + struct completion cmp; }; static inline struct dev_dax *to_dev_dax(struct device *dev) diff --git a/drivers/dax/device.c b/drivers/dax/device.c index f55829404a24..6ad964d7b077 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2016-2018 Intel Corporation. All rights reserved. */ +#include #include #include #include @@ -13,6 +14,38 @@ #include "dax-private.h" #include "bus.h" +static struct dev_dax *ref_to_dev_dax(struct percpu_ref *ref) +{ + return container_of(ref, struct dev_dax, ref); +} + +static void dev_dax_percpu_release(struct percpu_ref *ref) +{ + struct dev_dax *dev_dax = ref_to_dev_dax(ref); + + dev_dbg(&dev_dax->dev, "%s\n", __func__); + complete(&dev_dax->cmp); +} + +static void dev_dax_percpu_exit(void *data) +{ + struct percpu_ref *ref = data; + struct dev_dax *dev_dax = ref_to_dev_dax(ref); + + dev_dbg(&dev_dax->dev, "%s\n", __func__); + wait_for_completion(&dev_dax->cmp); + percpu_ref_exit(ref); +} + +static void dev_dax_percpu_kill(struct percpu_ref *data) +{ + struct percpu_ref *ref = data; + struct dev_dax *dev_dax = ref_to_dev_dax(ref); + + dev_dbg(&dev_dax->dev, "%s\n", __func__); + percpu_ref_kill(ref); +} + static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, const char *func) { @@ -416,10 +449,38 @@ static int dev_dax_probe(struct device *dev) { struct dev_dax *dev_dax = to_dev_dax(dev); struct dax_device *dax_dev = dev_dax->dax_dev; + struct resource *res = &dev_dax->region->res; struct inode *inode; struct cdev *cdev; + void *addr; int rc; + /* 1:1 map region resource range to device-dax instance range */ + if (!devm_request_mem_region(dev, res->start, resource_size(res), + dev_name(dev))) { + dev_warn(dev, "could not reserve region %pR\n", res); + return -EBUSY; + } + + init_completion(&dev_dax->cmp); + rc = percpu_ref_init(&dev_dax->ref, dev_dax_percpu_release, 0, + GFP_KERNEL); + if (rc) + return rc; + + rc = devm_add_action_or_reset(dev, dev_dax_percpu_exit, &dev_dax->ref); + if (rc) + return rc; + + dev_dax->pgmap.ref = &dev_dax->ref; + dev_dax->pgmap.kill = dev_dax_percpu_kill; + addr = devm_memremap_pages(dev, &dev_dax->pgmap); + if (IS_ERR(addr)) { + devm_remove_action(dev, dev_dax_percpu_exit, &dev_dax->ref); + percpu_ref_exit(&dev_dax->ref); + return PTR_ERR(addr); + } + inode = dax_inode(dax_dev); cdev = inode->i_cdev; cdev_init(cdev, &dax_fops); diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index e1b50d8fd1f8..d3cefa7868ac 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -18,54 +18,16 @@ #include "../nvdimm/nd.h" #include "bus.h" -struct dax_pmem { - struct device *dev; - struct percpu_ref ref; - struct dev_pagemap pgmap; - struct completion cmp; -}; - -static struct dax_pmem *to_dax_pmem(struct percpu_ref *ref) -{ - return container_of(ref, struct dax_pmem, ref); -} - -static void dax_pmem_percpu_release(struct percpu_ref *ref) -{ - struct dax_pmem *dax_pmem = to_dax_pmem(ref); - - dev_dbg(dax_pmem->dev, "trace\n"); - complete(&dax_pmem->cmp); -} - -static void dax_pmem_percpu_exit(void *data) -{ - struct percpu_ref *ref = data; - struct dax_pmem *dax_pmem = to_dax_pmem(ref); - - dev_dbg(dax_pmem->dev, "trace\n"); - wait_for_completion(&dax_pmem->cmp); - percpu_ref_exit(ref); -} - -static void dax_pmem_percpu_kill(struct percpu_ref *ref) -{ - struct dax_pmem *dax_pmem = to_dax_pmem(ref); - - dev_dbg(dax_pmem->dev, "trace\n"); - percpu_ref_kill(ref); -} - static int dax_pmem_probe(struct device *dev) { - void *addr; struct resource res; int rc, id, region_id; + resource_size_t offset; struct nd_pfn_sb *pfn_sb; struct dev_dax *dev_dax; - struct dax_pmem *dax_pmem; struct nd_namespace_io *nsio; struct dax_region *dax_region; + struct dev_pagemap pgmap = { 0 }; struct nd_namespace_common *ndns; struct nd_dax *nd_dax = to_nd_dax(dev); struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; @@ -75,61 +37,37 @@ static int dax_pmem_probe(struct device *dev) return PTR_ERR(ndns); nsio = to_nd_namespace_io(&ndns->dev); - dax_pmem = devm_kzalloc(dev, sizeof(*dax_pmem), GFP_KERNEL); - if (!dax_pmem) - return -ENOMEM; - /* parse the 'pfn' info block via ->rw_bytes */ rc = devm_nsio_enable(dev, nsio); if (rc) return rc; - rc = nvdimm_setup_pfn(nd_pfn, &dax_pmem->pgmap); + rc = nvdimm_setup_pfn(nd_pfn, &pgmap); if (rc) return rc; devm_nsio_disable(dev, nsio); - pfn_sb = nd_pfn->pfn_sb; - - if (!devm_request_mem_region(dev, nsio->res.start, - resource_size(&nsio->res), + /* reserve the metadata area, device-dax will reserve the data */ + pfn_sb = nd_pfn->pfn_sb; + offset = le64_to_cpu(pfn_sb->dataoff); + if (!devm_request_mem_region(dev, nsio->res.start, offset, dev_name(&ndns->dev))) { - dev_warn(dev, "could not reserve region %pR\n", &nsio->res); - return -EBUSY; - } - - dax_pmem->dev = dev; - init_completion(&dax_pmem->cmp); - rc = percpu_ref_init(&dax_pmem->ref, dax_pmem_percpu_release, 0, - GFP_KERNEL); - if (rc) - return rc; - - rc = devm_add_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref); - if (rc) { - percpu_ref_exit(&dax_pmem->ref); - return rc; - } - - dax_pmem->pgmap.ref = &dax_pmem->ref; - dax_pmem->pgmap.kill = dax_pmem_percpu_kill; - addr = devm_memremap_pages(dev, &dax_pmem->pgmap); - if (IS_ERR(addr)) - return PTR_ERR(addr); - - /* adjust the dax_region resource to the start of data */ - memcpy(&res, &dax_pmem->pgmap.res, sizeof(res)); - res.start += le64_to_cpu(pfn_sb->dataoff); + dev_warn(dev, "could not reserve metadata\n"); + return -EBUSY; + } rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); if (rc != 2) return -EINVAL; + /* adjust the dax_region resource to the start of data */ + memcpy(&res, &pgmap.res, sizeof(res)); + res.start += offset; dax_region = alloc_dax_region(dev, region_id, &res, le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP); if (!dax_region) return -ENOMEM; - dev_dax = devm_create_dev_dax(dax_region, id); + dev_dax = devm_create_dev_dax(dax_region, id, &pgmap); /* child dev_dax instances now own the lifetime of the dax_region */ dax_region_put(dax_region); -- cgit v1.2.3 From d200781ef237a354d918ceff5cee350d88a93d42 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 7 Nov 2018 15:31:23 -0800 Subject: device-dax: Add support for a dax override driver Introduce the 'new_id' concept for enabling a custom device-driver attach policy for dax-bus drivers. The intended use is to have a mechanism for hot-plugging device-dax ranges into the page allocator on-demand. With this in place the default policy of using device-dax for performance differentiated memory can be overridden by user-space policy that can arrange for the memory range to be managed as 'System RAM' with user-defined NUMA and other performance attributes. Signed-off-by: Dan Williams --- drivers/dax/bus.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++-- drivers/dax/bus.h | 10 +++- drivers/dax/device.c | 11 ++-- 3 files changed, 156 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 69aae2cbd45f..17af6fbc3be5 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -2,11 +2,21 @@ /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */ #include #include +#include +#include #include #include #include "dax-private.h" #include "bus.h" +static DEFINE_MUTEX(dax_bus_lock); + +#define DAX_NAME_LEN 30 +struct dax_id { + struct list_head list; + char dev_name[DAX_NAME_LEN]; +}; + static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { /* @@ -16,22 +26,115 @@ static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return add_uevent_var(env, "MODALIAS=" DAX_DEVICE_MODALIAS_FMT, 0); } +static struct dax_device_driver *to_dax_drv(struct device_driver *drv) +{ + return container_of(drv, struct dax_device_driver, drv); +} + +static struct dax_id *__dax_match_id(struct dax_device_driver *dax_drv, + const char *dev_name) +{ + struct dax_id *dax_id; + + lockdep_assert_held(&dax_bus_lock); + + list_for_each_entry(dax_id, &dax_drv->ids, list) + if (sysfs_streq(dax_id->dev_name, dev_name)) + return dax_id; + return NULL; +} + +static int dax_match_id(struct dax_device_driver *dax_drv, struct device *dev) +{ + int match; + + mutex_lock(&dax_bus_lock); + match = !!__dax_match_id(dax_drv, dev_name(dev)); + mutex_unlock(&dax_bus_lock); + + return match; +} + +static ssize_t do_id_store(struct device_driver *drv, const char *buf, + size_t count, bool add) +{ + struct dax_device_driver *dax_drv = to_dax_drv(drv); + unsigned int region_id, id; + char devname[DAX_NAME_LEN]; + struct dax_id *dax_id; + ssize_t rc = count; + int fields; + + fields = sscanf(buf, "dax%d.%d", ®ion_id, &id); + if (fields != 2) + return -EINVAL; + sprintf(devname, "dax%d.%d", region_id, id); + if (!sysfs_streq(buf, devname)) + return -EINVAL; + + mutex_lock(&dax_bus_lock); + dax_id = __dax_match_id(dax_drv, buf); + if (!dax_id) { + if (add) { + dax_id = kzalloc(sizeof(*dax_id), GFP_KERNEL); + if (dax_id) { + strncpy(dax_id->dev_name, buf, DAX_NAME_LEN); + list_add(&dax_id->list, &dax_drv->ids); + } else + rc = -ENOMEM; + } else + /* nothing to remove */; + } else if (!add) { + list_del(&dax_id->list); + kfree(dax_id); + } else + /* dax_id already added */; + mutex_unlock(&dax_bus_lock); + return rc; +} + +static ssize_t new_id_store(struct device_driver *drv, const char *buf, + size_t count) +{ + return do_id_store(drv, buf, count, true); +} +static DRIVER_ATTR_WO(new_id); + +static ssize_t remove_id_store(struct device_driver *drv, const char *buf, + size_t count) +{ + return do_id_store(drv, buf, count, false); +} +static DRIVER_ATTR_WO(remove_id); + +static struct attribute *dax_drv_attrs[] = { + &driver_attr_new_id.attr, + &driver_attr_remove_id.attr, + NULL, +}; +ATTRIBUTE_GROUPS(dax_drv); + static int dax_bus_match(struct device *dev, struct device_driver *drv); static struct bus_type dax_bus_type = { .name = "dax", .uevent = dax_bus_uevent, .match = dax_bus_match, + .drv_groups = dax_drv_groups, }; static int dax_bus_match(struct device *dev, struct device_driver *drv) { + struct dax_device_driver *dax_drv = to_dax_drv(drv); + /* - * The drivers that can register on the 'dax' bus are private to - * drivers/dax/ so any device and driver on the bus always - * match. + * All but the 'device-dax' driver, which has 'match_always' + * set, requires an exact id match. */ - return 1; + if (dax_drv->match_always) + return 1; + + return dax_match_id(dax_drv, dev); } /* @@ -273,17 +376,49 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, } EXPORT_SYMBOL_GPL(devm_create_dev_dax); -int __dax_driver_register(struct device_driver *drv, +static int match_always_count; + +int __dax_driver_register(struct dax_device_driver *dax_drv, struct module *module, const char *mod_name) { + struct device_driver *drv = &dax_drv->drv; + int rc = 0; + + INIT_LIST_HEAD(&dax_drv->ids); drv->owner = module; drv->name = mod_name; drv->mod_name = mod_name; drv->bus = &dax_bus_type; + + /* there can only be one default driver */ + mutex_lock(&dax_bus_lock); + match_always_count += dax_drv->match_always; + if (match_always_count > 1) { + match_always_count--; + WARN_ON(1); + rc = -EINVAL; + } + mutex_unlock(&dax_bus_lock); + if (rc) + return rc; return driver_register(drv); } EXPORT_SYMBOL_GPL(__dax_driver_register); +void dax_driver_unregister(struct dax_device_driver *dax_drv) +{ + struct dax_id *dax_id, *_id; + + mutex_lock(&dax_bus_lock); + match_always_count -= dax_drv->match_always; + list_for_each_entry_safe(dax_id, _id, &dax_drv->ids, list) { + list_del(&dax_id->list); + kfree(dax_id); + } + mutex_unlock(&dax_bus_lock); +} +EXPORT_SYMBOL_GPL(dax_driver_unregister); + int __init dax_bus_init(void) { return bus_register(&dax_bus_type); diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index e08e0c394983..395ab812367c 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -12,10 +12,18 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, unsigned long flags); struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, struct dev_pagemap *pgmap); -int __dax_driver_register(struct device_driver *drv, + +struct dax_device_driver { + struct device_driver drv; + struct list_head ids; + int match_always; +}; + +int __dax_driver_register(struct dax_device_driver *dax_drv, struct module *module, const char *mod_name); #define dax_driver_register(driver) \ __dax_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) +void dax_driver_unregister(struct dax_device_driver *dax_drv); void kill_dev_dax(struct dev_dax *dev_dax); /* diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 6ad964d7b077..ad3120395f7a 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -504,9 +504,12 @@ static int dev_dax_remove(struct device *dev) return 0; } -static struct device_driver device_dax_driver = { - .probe = dev_dax_probe, - .remove = dev_dax_remove, +static struct dax_device_driver device_dax_driver = { + .drv = { + .probe = dev_dax_probe, + .remove = dev_dax_remove, + }, + .match_always = 1, }; static int __init dax_init(void) @@ -516,7 +519,7 @@ static int __init dax_init(void) static void __exit dax_exit(void) { - driver_unregister(&device_dax_driver); + dax_driver_unregister(&device_dax_driver); } MODULE_AUTHOR("Intel Corporation"); -- cgit v1.2.3 From 730926c3b0998943654019f00296cf8e3b02277e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 16 Jul 2017 13:51:53 -0700 Subject: device-dax: Add /sys/class/dax backwards compatibility On the expectation that some environments may not upgrade libdaxctl (userspace component that depends on the /sys/class/dax hierarchy), provide a default / legacy dax_pmem_compat driver. The dax_pmem_compat driver implements the original /sys/class/dax sysfs layout rather than /sys/bus/dax. When userspace is upgraded it can blacklist this module and switch to the dax_pmem driver going forward. CONFIG_DEV_DAX_PMEM_COMPAT and supporting code will be deleted according to the dax_pmem entry in Documentation/ABI/obsolete/. Signed-off-by: Dan Williams --- drivers/dax/Kconfig | 12 ++++++- drivers/dax/Makefile | 4 +-- drivers/dax/bus.c | 29 ++++++++++++--- drivers/dax/bus.h | 26 ++++++++++++-- drivers/dax/device.c | 9 +++-- drivers/dax/pmem.c | 90 ----------------------------------------------- drivers/dax/pmem/Makefile | 7 ++++ drivers/dax/pmem/compat.c | 73 ++++++++++++++++++++++++++++++++++++++ drivers/dax/pmem/core.c | 69 ++++++++++++++++++++++++++++++++++++ drivers/dax/pmem/pmem.c | 40 +++++++++++++++++++++ 10 files changed, 256 insertions(+), 103 deletions(-) delete mode 100644 drivers/dax/pmem.c create mode 100644 drivers/dax/pmem/Makefile create mode 100644 drivers/dax/pmem/compat.c create mode 100644 drivers/dax/pmem/core.c create mode 100644 drivers/dax/pmem/pmem.c (limited to 'drivers') diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig index e0700bf4893a..6fc96f03920e 100644 --- a/drivers/dax/Kconfig +++ b/drivers/dax/Kconfig @@ -23,12 +23,22 @@ config DEV_DAX config DEV_DAX_PMEM tristate "PMEM DAX: direct access to persistent memory" depends on LIBNVDIMM && NVDIMM_DAX && DEV_DAX + depends on m # until we can kill DEV_DAX_PMEM_COMPAT default DEV_DAX help Support raw access to persistent memory. Note that this driver consumes memory ranges allocated and exported by the libnvdimm sub-system. - Say Y if unsure + Say M if unsure + +config DEV_DAX_PMEM_COMPAT + tristate "PMEM DAX: support the deprecated /sys/class/dax interface" + depends on DEV_DAX_PMEM + default DEV_DAX_PMEM + help + Older versions of the libdaxctl library expect to find all + device-dax instances under /sys/class/dax. If libdaxctl in + your distribution is older than v58 say M, otherwise say N. endif diff --git a/drivers/dax/Makefile b/drivers/dax/Makefile index 658e6b9b1d74..233bbffccbe6 100644 --- a/drivers/dax/Makefile +++ b/drivers/dax/Makefile @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DAX) += dax.o obj-$(CONFIG_DEV_DAX) += device_dax.o -obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o dax-y := super.o dax-y += bus.o -dax_pmem-y := pmem.o device_dax-y := device.o + +obj-y += pmem/ diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 17af6fbc3be5..568168500217 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -9,6 +9,8 @@ #include "dax-private.h" #include "bus.h" +static struct class *dax_class; + static DEFINE_MUTEX(dax_bus_lock); #define DAX_NAME_LEN 30 @@ -310,8 +312,8 @@ static void unregister_dev_dax(void *dev) put_device(dev); } -struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, - struct dev_pagemap *pgmap) +struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id, + struct dev_pagemap *pgmap, enum dev_dax_subsys subsys) { struct device *parent = dax_region->dev; struct dax_device *dax_dev; @@ -350,7 +352,10 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, inode = dax_inode(dax_dev); dev->devt = inode->i_rdev; - dev->bus = &dax_bus_type; + if (subsys == DEV_DAX_BUS) + dev->bus = &dax_bus_type; + else + dev->class = dax_class; dev->parent = parent; dev->groups = dax_attribute_groups; dev->release = dev_dax_release; @@ -374,7 +379,7 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, return ERR_PTR(rc); } -EXPORT_SYMBOL_GPL(devm_create_dev_dax); +EXPORT_SYMBOL_GPL(__devm_create_dev_dax); static int match_always_count; @@ -407,6 +412,7 @@ EXPORT_SYMBOL_GPL(__dax_driver_register); void dax_driver_unregister(struct dax_device_driver *dax_drv) { + struct device_driver *drv = &dax_drv->drv; struct dax_id *dax_id, *_id; mutex_lock(&dax_bus_lock); @@ -416,15 +422,28 @@ void dax_driver_unregister(struct dax_device_driver *dax_drv) kfree(dax_id); } mutex_unlock(&dax_bus_lock); + driver_unregister(drv); } EXPORT_SYMBOL_GPL(dax_driver_unregister); int __init dax_bus_init(void) { - return bus_register(&dax_bus_type); + int rc; + + if (IS_ENABLED(CONFIG_DEV_DAX_PMEM_COMPAT)) { + dax_class = class_create(THIS_MODULE, "dax"); + if (IS_ERR(dax_class)) + return PTR_ERR(dax_class); + } + + rc = bus_register(&dax_bus_type); + if (rc) + class_destroy(dax_class); + return rc; } void __exit dax_bus_exit(void) { bus_unregister(&dax_bus_type); + class_destroy(dax_class); } diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index 395ab812367c..ce977552ffb5 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -2,7 +2,8 @@ /* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ #ifndef __DAX_BUS_H__ #define __DAX_BUS_H__ -struct device; +#include + struct dev_dax; struct resource; struct dax_device; @@ -10,8 +11,23 @@ struct dax_region; void dax_region_put(struct dax_region *dax_region); struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, unsigned long flags); -struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, - struct dev_pagemap *pgmap); + +enum dev_dax_subsys { + DEV_DAX_BUS, + DEV_DAX_CLASS, +}; + +struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id, + struct dev_pagemap *pgmap, enum dev_dax_subsys subsys); + +static inline struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, + int id, struct dev_pagemap *pgmap) +{ + return __devm_create_dev_dax(dax_region, id, pgmap, DEV_DAX_BUS); +} + +/* to be deleted when DEV_DAX_CLASS is removed */ +struct dev_dax *__dax_pmem_probe(struct device *dev, enum dev_dax_subsys subsys); struct dax_device_driver { struct device_driver drv; @@ -26,6 +42,10 @@ int __dax_driver_register(struct dax_device_driver *dax_drv, void dax_driver_unregister(struct dax_device_driver *dax_drv); void kill_dev_dax(struct dev_dax *dev_dax); +#if IS_ENABLED(CONFIG_DEV_DAX_PMEM_COMPAT) +int dev_dax_probe(struct device *dev); +#endif + /* * While run_dax() is potentially a generic operation that could be * defined in include/linux/dax.h we don't want to grow any users diff --git a/drivers/dax/device.c b/drivers/dax/device.c index ad3120395f7a..e428468ab661 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -445,7 +445,7 @@ static void dev_dax_kill(void *dev_dax) kill_dev_dax(dev_dax); } -static int dev_dax_probe(struct device *dev) +int dev_dax_probe(struct device *dev) { struct dev_dax *dev_dax = to_dev_dax(dev); struct dax_device *dax_dev = dev_dax->dax_dev; @@ -484,7 +484,11 @@ static int dev_dax_probe(struct device *dev) inode = dax_inode(dax_dev); cdev = inode->i_cdev; cdev_init(cdev, &dax_fops); - cdev->owner = dev->driver->owner; + if (dev->class) { + /* for the CONFIG_DEV_DAX_PMEM_COMPAT case */ + cdev->owner = dev->parent->driver->owner; + } else + cdev->owner = dev->driver->owner; cdev_set_parent(cdev, &dev->kobj); rc = cdev_add(cdev, dev->devt, 1); if (rc) @@ -497,6 +501,7 @@ static int dev_dax_probe(struct device *dev) run_dax(dax_dev); return devm_add_action_or_reset(dev, dev_dax_kill, dev_dax); } +EXPORT_SYMBOL_GPL(dev_dax_probe); static int dev_dax_remove(struct device *dev) { diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c deleted file mode 100644 index d3cefa7868ac..000000000000 --- a/drivers/dax/pmem.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#include -#include -#include -#include -#include "../nvdimm/pfn.h" -#include "../nvdimm/nd.h" -#include "bus.h" - -static int dax_pmem_probe(struct device *dev) -{ - struct resource res; - int rc, id, region_id; - resource_size_t offset; - struct nd_pfn_sb *pfn_sb; - struct dev_dax *dev_dax; - struct nd_namespace_io *nsio; - struct dax_region *dax_region; - struct dev_pagemap pgmap = { 0 }; - struct nd_namespace_common *ndns; - struct nd_dax *nd_dax = to_nd_dax(dev); - struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; - - ndns = nvdimm_namespace_common_probe(dev); - if (IS_ERR(ndns)) - return PTR_ERR(ndns); - nsio = to_nd_namespace_io(&ndns->dev); - - /* parse the 'pfn' info block via ->rw_bytes */ - rc = devm_nsio_enable(dev, nsio); - if (rc) - return rc; - rc = nvdimm_setup_pfn(nd_pfn, &pgmap); - if (rc) - return rc; - devm_nsio_disable(dev, nsio); - - /* reserve the metadata area, device-dax will reserve the data */ - pfn_sb = nd_pfn->pfn_sb; - offset = le64_to_cpu(pfn_sb->dataoff); - if (!devm_request_mem_region(dev, nsio->res.start, offset, - dev_name(&ndns->dev))) { - dev_warn(dev, "could not reserve metadata\n"); - return -EBUSY; - } - - rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); - if (rc != 2) - return -EINVAL; - - /* adjust the dax_region resource to the start of data */ - memcpy(&res, &pgmap.res, sizeof(res)); - res.start += offset; - dax_region = alloc_dax_region(dev, region_id, &res, - le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP); - if (!dax_region) - return -ENOMEM; - - dev_dax = devm_create_dev_dax(dax_region, id, &pgmap); - - /* child dev_dax instances now own the lifetime of the dax_region */ - dax_region_put(dax_region); - - return PTR_ERR_OR_ZERO(dev_dax); -} - -static struct nd_device_driver dax_pmem_driver = { - .probe = dax_pmem_probe, - .drv = { - .name = "dax_pmem", - }, - .type = ND_DRIVER_DAX_PMEM, -}; - -module_nd_driver(dax_pmem_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Intel Corporation"); -MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM); diff --git a/drivers/dax/pmem/Makefile b/drivers/dax/pmem/Makefile new file mode 100644 index 000000000000..e2e79bd3fdcf --- /dev/null +++ b/drivers/dax/pmem/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o +obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem_core.o +obj-$(CONFIG_DEV_DAX_PMEM_COMPAT) += dax_pmem_compat.o + +dax_pmem-y := pmem.o +dax_pmem_core-y := core.o +dax_pmem_compat-y := compat.o diff --git a/drivers/dax/pmem/compat.c b/drivers/dax/pmem/compat.c new file mode 100644 index 000000000000..d7b15e6f30c5 --- /dev/null +++ b/drivers/dax/pmem/compat.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ +#include +#include +#include +#include +#include +#include "../bus.h" + +/* we need the private definitions to implement compat suport */ +#include "../dax-private.h" + +static int dax_pmem_compat_probe(struct device *dev) +{ + struct dev_dax *dev_dax = __dax_pmem_probe(dev, DEV_DAX_CLASS); + int rc; + + if (IS_ERR(dev_dax)) + return PTR_ERR(dev_dax); + + if (!devres_open_group(&dev_dax->dev, dev_dax, GFP_KERNEL)) + return -ENOMEM; + + device_lock(&dev_dax->dev); + rc = dev_dax_probe(&dev_dax->dev); + device_unlock(&dev_dax->dev); + + devres_close_group(&dev_dax->dev, dev_dax); + if (rc) + devres_release_group(&dev_dax->dev, dev_dax); + + return rc; +} + +static int dax_pmem_compat_release(struct device *dev, void *data) +{ + device_lock(dev); + devres_release_group(dev, to_dev_dax(dev)); + device_unlock(dev); + + return 0; +} + +static int dax_pmem_compat_remove(struct device *dev) +{ + device_for_each_child(dev, NULL, dax_pmem_compat_release); + return 0; +} + +static struct nd_device_driver dax_pmem_compat_driver = { + .probe = dax_pmem_compat_probe, + .remove = dax_pmem_compat_remove, + .drv = { + .name = "dax_pmem_compat", + }, + .type = ND_DRIVER_DAX_PMEM, +}; + +static int __init dax_pmem_compat_init(void) +{ + return nd_driver_register(&dax_pmem_compat_driver); +} +module_init(dax_pmem_compat_init); + +static void __exit dax_pmem_compat_exit(void) +{ + driver_unregister(&dax_pmem_compat_driver.drv); +} +module_exit(dax_pmem_compat_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM); diff --git a/drivers/dax/pmem/core.c b/drivers/dax/pmem/core.c new file mode 100644 index 000000000000..bdcff1b14e95 --- /dev/null +++ b/drivers/dax/pmem/core.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ +#include +#include +#include +#include "../../nvdimm/pfn.h" +#include "../../nvdimm/nd.h" +#include "../bus.h" + +struct dev_dax *__dax_pmem_probe(struct device *dev, enum dev_dax_subsys subsys) +{ + struct resource res; + int rc, id, region_id; + resource_size_t offset; + struct nd_pfn_sb *pfn_sb; + struct dev_dax *dev_dax; + struct nd_namespace_io *nsio; + struct dax_region *dax_region; + struct dev_pagemap pgmap = { 0 }; + struct nd_namespace_common *ndns; + struct nd_dax *nd_dax = to_nd_dax(dev); + struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; + + ndns = nvdimm_namespace_common_probe(dev); + if (IS_ERR(ndns)) + return ERR_CAST(ndns); + nsio = to_nd_namespace_io(&ndns->dev); + + /* parse the 'pfn' info block via ->rw_bytes */ + rc = devm_nsio_enable(dev, nsio); + if (rc) + return ERR_PTR(rc); + rc = nvdimm_setup_pfn(nd_pfn, &pgmap); + if (rc) + return ERR_PTR(rc); + devm_nsio_disable(dev, nsio); + + /* reserve the metadata area, device-dax will reserve the data */ + pfn_sb = nd_pfn->pfn_sb; + offset = le64_to_cpu(pfn_sb->dataoff); + if (!devm_request_mem_region(dev, nsio->res.start, offset, + dev_name(&ndns->dev))) { + dev_warn(dev, "could not reserve metadata\n"); + return ERR_PTR(-EBUSY); + } + + rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); + if (rc != 2) + return ERR_PTR(-EINVAL); + + /* adjust the dax_region resource to the start of data */ + memcpy(&res, &pgmap.res, sizeof(res)); + res.start += offset; + dax_region = alloc_dax_region(dev, region_id, &res, + le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP); + if (!dax_region) + return ERR_PTR(-ENOMEM); + + dev_dax = __devm_create_dev_dax(dax_region, id, &pgmap, subsys); + + /* child dev_dax instances now own the lifetime of the dax_region */ + dax_region_put(dax_region); + + return dev_dax; +} +EXPORT_SYMBOL_GPL(__dax_pmem_probe); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/dax/pmem/pmem.c b/drivers/dax/pmem/pmem.c new file mode 100644 index 000000000000..0ae4238a0ef8 --- /dev/null +++ b/drivers/dax/pmem/pmem.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ +#include +#include +#include +#include +#include +#include "../bus.h" + +static int dax_pmem_probe(struct device *dev) +{ + return PTR_ERR_OR_ZERO(__dax_pmem_probe(dev, DEV_DAX_BUS)); +} + +static struct nd_device_driver dax_pmem_driver = { + .probe = dax_pmem_probe, + .drv = { + .name = "dax_pmem", + }, + .type = ND_DRIVER_DAX_PMEM, +}; + +static int __init dax_pmem_init(void) +{ + return nd_driver_register(&dax_pmem_driver); +} +module_init(dax_pmem_init); + +static void __exit dax_pmem_exit(void) +{ + driver_unregister(&dax_pmem_driver.drv); +} +module_exit(dax_pmem_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Intel Corporation"); +#if !IS_ENABLED(CONFIG_DEV_DAX_PMEM_COMPAT) +/* For compat builds, don't load this module by default */ +MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM); +#endif -- cgit v1.2.3 From 8fc5c73554db0ac18c0c6ac5b2099ab917f83bdf Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 9 Nov 2018 12:43:07 -0800 Subject: acpi/nfit, device-dax: Identify differentiated memory with a unique numa-node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Persistent memory, as described by the ACPI NFIT (NVDIMM Firmware Interface Table), is the first known instance of a memory range described by a unique "target" proximity domain. Where "initiator" and "target" proximity domains is an approach that the ACPI HMAT (Heterogeneous Memory Attributes Table) uses to described the unique performance properties of a memory range relative to a given initiator (e.g. CPU or DMA device). Currently the numa-node for a /dev/pmemX block-device or /dev/daxX.Y char-device follows the traditional notion of 'numa-node' where the attribute conveys the closest online numa-node. That numa-node attribute is useful for cpu-binding and memory-binding processes *near* the device. However, when the memory range backing a 'pmem', or 'dax' device is onlined (memory hot-add) the memory-only-numa-node representing that address needs to be differentiated from the set of online nodes. In other words, the numa-node association of the device depends on whether you can bind processes *near* the cpu-numa-node in the offline device-case, or bind process *on* the memory-range directly after the backing address range is onlined. Allow for the case that platform firmware describes persistent memory with a unique proximity domain, i.e. when it is distinct from the proximity of DRAM and CPUs that are on the same socket. Plumb the Linux numa-node translation of that proximity through the libnvdimm region device to namespaces that are in device-dax mode. With this in place the proposed kmem driver [1] can optionally discover a unique numa-node number for the address range as it transitions the memory from an offline state managed by a device-driver to an online memory range managed by the core-mm. [1]: https://lore.kernel.org/lkml/20181022201317.8558C1D8@viggo.jf.intel.com Reported-by: Fan Du Cc: Michael Ellerman Cc: "Oliver O'Halloran" Cc: Dave Hansen Cc: Jérôme Glisse Reviewed-by: Yang Shi Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 8 ++++++-- drivers/acpi/numa.c | 1 + drivers/dax/bus.c | 4 +++- drivers/dax/bus.h | 3 ++- drivers/dax/dax-private.h | 4 ++++ drivers/dax/pmem/core.c | 4 +++- drivers/nvdimm/e820.c | 1 + drivers/nvdimm/nd.h | 2 +- drivers/nvdimm/of_pmem.c | 1 + drivers/nvdimm/region_devs.c | 1 + 10 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 011d3db19c80..475899974c70 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2869,11 +2869,15 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc, ndr_desc->res = &res; ndr_desc->provider_data = nfit_spa; ndr_desc->attr_groups = acpi_nfit_region_attribute_groups; - if (spa->flags & ACPI_NFIT_PROXIMITY_VALID) + if (spa->flags & ACPI_NFIT_PROXIMITY_VALID) { ndr_desc->numa_node = acpi_map_pxm_to_online_node( spa->proximity_domain); - else + ndr_desc->target_node = acpi_map_pxm_to_node( + spa->proximity_domain); + } else { ndr_desc->numa_node = NUMA_NO_NODE; + ndr_desc->target_node = NUMA_NO_NODE; + } /* * Persistence domain bits are hierarchical, if diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 274699463b4f..b9d86babb13a 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -84,6 +84,7 @@ int acpi_map_pxm_to_node(int pxm) return node; } +EXPORT_SYMBOL(acpi_map_pxm_to_node); /** * acpi_map_pxm_to_online_node - Map proximity ID to online node diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 568168500217..c620ad52d7e5 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -214,7 +214,7 @@ static void dax_region_unregister(void *region) } struct dax_region *alloc_dax_region(struct device *parent, int region_id, - struct resource *res, unsigned int align, + struct resource *res, int target_node, unsigned int align, unsigned long pfn_flags) { struct dax_region *dax_region; @@ -244,6 +244,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, dax_region->id = region_id; dax_region->align = align; dax_region->dev = parent; + dax_region->target_node = target_node; if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) { kfree(dax_region); return NULL; @@ -348,6 +349,7 @@ struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id, dev_dax->dax_dev = dax_dev; dev_dax->region = dax_region; + dev_dax->target_node = dax_region->target_node; kref_get(&dax_region->kref); inode = dax_inode(dax_dev); diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index ce977552ffb5..8619e3299943 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -10,7 +10,8 @@ struct dax_device; struct dax_region; void dax_region_put(struct dax_region *dax_region); struct dax_region *alloc_dax_region(struct device *parent, int region_id, - struct resource *res, unsigned int align, unsigned long flags); + struct resource *res, int target_node, unsigned int align, + unsigned long flags); enum dev_dax_subsys { DEV_DAX_BUS, diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index a82ce48f5884..a45612148ca0 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -26,6 +26,7 @@ void dax_bus_exit(void); /** * struct dax_region - mapping infrastructure for dax devices * @id: kernel-wide unique region for a memory range + * @target_node: effective numa node if this memory range is onlined * @kref: to pin while other agents have a need to do lookups * @dev: parent device backing this region * @align: allocation and mapping alignment for child dax devices @@ -34,6 +35,7 @@ void dax_bus_exit(void); */ struct dax_region { int id; + int target_node; struct kref kref; struct device *dev; unsigned int align; @@ -46,6 +48,7 @@ struct dax_region { * data while the device is activated in the driver. * @region - parent region * @dax_dev - core dax functionality + * @target_node: effective numa node if dev_dax memory range is onlined * @dev - device core * @pgmap - pgmap for memmap setup / lifetime (driver owned) * @ref: pgmap reference count (driver owned) @@ -54,6 +57,7 @@ struct dax_region { struct dev_dax { struct dax_region *region; struct dax_device *dax_dev; + int target_node; struct device dev; struct dev_pagemap pgmap; struct percpu_ref ref; diff --git a/drivers/dax/pmem/core.c b/drivers/dax/pmem/core.c index bdcff1b14e95..f71019ce0647 100644 --- a/drivers/dax/pmem/core.c +++ b/drivers/dax/pmem/core.c @@ -20,6 +20,7 @@ struct dev_dax *__dax_pmem_probe(struct device *dev, enum dev_dax_subsys subsys) struct nd_namespace_common *ndns; struct nd_dax *nd_dax = to_nd_dax(dev); struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; + struct nd_region *nd_region = to_nd_region(dev->parent); ndns = nvdimm_namespace_common_probe(dev); if (IS_ERR(ndns)) @@ -52,7 +53,8 @@ struct dev_dax *__dax_pmem_probe(struct device *dev, enum dev_dax_subsys subsys) memcpy(&res, &pgmap.res, sizeof(res)); res.start += offset; dax_region = alloc_dax_region(dev, region_id, &res, - le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP); + nd_region->target_node, le32_to_cpu(pfn_sb->align), + PFN_DEV|PFN_MAP); if (!dax_region) return ERR_PTR(-ENOMEM); diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c index 521eaf53a52a..36be9b619187 100644 --- a/drivers/nvdimm/e820.c +++ b/drivers/nvdimm/e820.c @@ -47,6 +47,7 @@ static int e820_register_one(struct resource *res, void *data) ndr_desc.res = res; ndr_desc.attr_groups = e820_pmem_region_attribute_groups; ndr_desc.numa_node = e820_range_to_nid(res->start); + ndr_desc.target_node = ndr_desc.numa_node; set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) return -ENXIO; diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index cfde992684e7..0b3d7595b3cb 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -153,7 +153,7 @@ struct nd_region { u16 ndr_mappings; u64 ndr_size; u64 ndr_start; - int id, num_lanes, ro, numa_node; + int id, num_lanes, ro, numa_node, target_node; void *provider_data; struct kernfs_node *bb_state; struct badblocks bb; diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c index 0a701837dfc0..ecaaa27438e2 100644 --- a/drivers/nvdimm/of_pmem.c +++ b/drivers/nvdimm/of_pmem.c @@ -68,6 +68,7 @@ static int of_pmem_region_probe(struct platform_device *pdev) memset(&ndr_desc, 0, sizeof(ndr_desc)); ndr_desc.attr_groups = region_attr_groups; ndr_desc.numa_node = dev_to_node(&pdev->dev); + ndr_desc.target_node = ndr_desc.numa_node; ndr_desc.res = &pdev->resource[i]; ndr_desc.of_node = np; set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index e2818f94f292..caf2f3129ccd 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -1065,6 +1065,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, nd_region->flags = ndr_desc->flags; nd_region->ro = ro; nd_region->numa_node = ndr_desc->numa_node; + nd_region->target_node = ndr_desc->target_node; ida_init(&nd_region->ns_ida); ida_init(&nd_region->btt_ida); ida_init(&nd_region->pfn_ida); -- cgit v1.2.3 From 60042a22be4e8e565db0a82acb84ee4b348b17c9 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 7 Nov 2018 23:26:01 +0800 Subject: remoteproc: debug: add crash debugfs node so we can trigger the crash manully which could: 1.test the crash handling code path more easily 2.update the firmware without reboot kernel Signed-off-by: Xiang Xiao Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_debugfs.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index e90135c64af0..f330a9ad014f 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -155,6 +155,30 @@ static const struct file_operations rproc_recovery_ops = { .llseek = generic_file_llseek, }; +/* expose the crash trigger via debugfs */ +static ssize_t +rproc_crash_write(struct file *filp, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + unsigned int type; + int ret; + + ret = kstrtouint_from_user(user_buf, count, 0, &type); + if (ret < 0) + return ret; + + rproc_report_crash(rproc, type); + + return count; +} + +static const struct file_operations rproc_crash_ops = { + .write = rproc_crash_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + /* Expose resource table content via debugfs */ static int rproc_rsc_table_show(struct seq_file *seq, void *p) { @@ -325,6 +349,8 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, &rproc_name_ops); debugfs_create_file("recovery", 0400, rproc->dbg_dir, rproc, &rproc_recovery_ops); + debugfs_create_file("crash", 0200, rproc->dbg_dir, + rproc, &rproc_crash_ops); debugfs_create_file("resource_table", 0400, rproc->dbg_dir, rproc, &rproc_rsc_table_ops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, -- cgit v1.2.3 From fff7fca51d400e67403efacf25612d8690e939c1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 26 Nov 2018 14:27:35 +0000 Subject: remoteproc: qcom: fix spelling mistake "Peripherial" -> "Peripheral" There is a spelling mistake in the module description text, fix it. Signed-off-by: Colin Ian King Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_wcnss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index b0e07e9f42d5..1152da49a18a 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -622,5 +622,5 @@ static void __exit wcnss_exit(void) } module_exit(wcnss_exit); -MODULE_DESCRIPTION("Qualcomm Peripherial Image Loader for Wireless Subsystem"); +MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Wireless Subsystem"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 80ec419c3404106c563aaf56aa6b516a59c4cdfb Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Sat, 29 Dec 2018 00:23:03 +0530 Subject: remoteproc: qcom: q6v5-mss: Add missing clocks for MSM8996 Proxy vote for QDSS clock and remove vote on handover interrupt to provide MSS PBL with access to STM hardware registers during boot. Add "snoc_axi" and "mnoc_axi" to the active clock list. Rename "gpll0_mss_clk" to "gpll0_mss" for consistency across SoCs. Fixes: 9f058fa2efb1 ("remoteproc: qcom: Add support for mss remoteproc on msm8996") Signed-off-by: Sibi Sankar Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 01be7314e176..cb5f0d3ac6a3 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1398,13 +1398,16 @@ static const struct rproc_hexagon_res msm8996_mss = { .proxy_clk_names = (char*[]){ "xo", "pnoc", + "qdss", NULL }, .active_clk_names = (char*[]){ "iface", "bus", "mem", - "gpll0_mss_clk", + "gpll0_mss", + "snoc_axi", + "mnoc_axi", NULL }, .need_mem_protection = true, -- cgit v1.2.3 From 47b874748d500020026ee43b386b5598e20f3a68 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Sat, 29 Dec 2018 00:23:05 +0530 Subject: remoteproc: qcom: q6v5-mss: Add missing regulator for MSM8996 Add proxy vote for pll supply on MSM8996 SoC. Fixes: 9f058fa2efb1 ("remoteproc: qcom: Add support for mss remoteproc on msm8996") Signed-off-by: Sibi Sankar Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index cb5f0d3ac6a3..c86dc40cfb8c 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1395,6 +1395,13 @@ static const struct rproc_hexagon_res sdm845_mss = { static const struct rproc_hexagon_res msm8996_mss = { .hexagon_mba_image = "mba.mbn", + .proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "pll", + .uA = 100000, + }, + {} + }, .proxy_clk_names = (char*[]){ "xo", "pnoc", -- cgit v1.2.3 From 2f6fa4ca37c57e56ea535c947f60060c69a3dc03 Mon Sep 17 00:00:00 2001 From: Marko Stankovic Date: Tue, 25 Dec 2018 23:35:31 +0100 Subject: staging: wilc1000: make function wilc_get_stats_async static Makes local function wilc_get_stats_async() static Cleans up sparse warning: symbol 'wilc_get_stats_async' was not declared. Should it be static? Signed-off-by: Marko Stankovic Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 70c854d939ce..5dae6e7155d3 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -1992,7 +1992,7 @@ int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level) return result; } -int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats) +static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats) { int result; struct host_if_msg *msg; -- cgit v1.2.3 From c706d4b744fb43477eeee2bb898968756e0232ad Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 26 Dec 2018 11:34:11 +0800 Subject: staging: erofs: fix return type of erofs_workgroup_get There exists a return type misuse (`int'->`bool') since all users assume it fails if only return value != 0, let's fix the return type to `int' instead of confusing `bool'. No logic changes. Signed-off-by: Gao Xiang Reviewed-by: Chao Yu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index e049d00c087a..49c587383315 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -252,7 +252,7 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp) } #endif -static inline bool erofs_workgroup_get(struct erofs_workgroup *grp, int *ocnt) +static inline int erofs_workgroup_get(struct erofs_workgroup *grp, int *ocnt) { int o; -- cgit v1.2.3 From 5777c306a42533ad17703b75dffbd17c1bd203dc Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Mon, 24 Dec 2018 10:12:23 +0000 Subject: staging: speakup: Fix coding style Replaced text ---help--- with help as per style check patch recommendation Signed-off-by: Daniel Acked-by: Samuel Thibault Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/Kconfig | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/speakup/Kconfig b/drivers/staging/speakup/Kconfig index efd6f4560d3e..d8ec780f7741 100644 --- a/drivers/staging/speakup/Kconfig +++ b/drivers/staging/speakup/Kconfig @@ -3,7 +3,7 @@ menu "Speakup console speech" config SPEAKUP depends on VT tristate "Speakup core" - ---help--- + help This is the Speakup screen reader. Think of it as a video console for blind people. If built in to the kernel, it can speak everything on the text console from @@ -43,7 +43,7 @@ config SPEAKUP if SPEAKUP config SPEAKUP_SYNTH_ACNTSA tristate "Accent SA synthesizer support" - ---help--- + help This is the Speakup driver for the Accent SA synthesizer. You can say y to build it into the kernel, or m to build it as a module. See the configuration @@ -52,7 +52,7 @@ config SPEAKUP_SYNTH_ACNTSA config SPEAKUP_SYNTH_ACNTPC tristate "Accent PC synthesizer support" depends on ISA || COMPILE_TEST - ---help--- + help This is the Speakup driver for the accent pc synthesizer. You can say y to build it into the kernel, or m to build it as a module. See the configuration @@ -60,7 +60,7 @@ config SPEAKUP_SYNTH_ACNTPC config SPEAKUP_SYNTH_APOLLO tristate "Apollo II synthesizer support" - ---help--- + help This is the Speakup driver for the Apollo II synthesizer. You can say y to build it into the kernel, or m to build it as a module. See the configuration @@ -68,7 +68,7 @@ config SPEAKUP_SYNTH_APOLLO config SPEAKUP_SYNTH_AUDPTR tristate "Audapter synthesizer support" - ---help--- + help This is the Speakup driver for the Audapter synthesizer. You can say y to build it into the kernel, or m to build it as a module. See the configuration help on the @@ -76,7 +76,7 @@ config SPEAKUP_SYNTH_AUDPTR config SPEAKUP_SYNTH_BNS tristate "Braille 'n' Speak synthesizer support" - ---help--- + help This is the Speakup driver for the Braille 'n' Speak synthesizer. You can say y to build it into the kernel, or m to build it as a module. See the configuration @@ -84,7 +84,7 @@ config SPEAKUP_SYNTH_BNS config SPEAKUP_SYNTH_DECTLK tristate "DECtalk Express synthesizer support" - ---help--- + help This is the Speakup driver for the DecTalk Express synthesizer. You can say y to build it into the kernel, @@ -93,7 +93,7 @@ config SPEAKUP_SYNTH_DECTLK config SPEAKUP_SYNTH_DECEXT tristate "DECtalk External (old) synthesizer support" - ---help--- + help This is the Speakup driver for the DecTalk External (old) synthesizer. You can say y to build it into the @@ -105,7 +105,7 @@ config SPEAKUP_SYNTH_DECPC depends on m depends on ISA || COMPILE_TEST tristate "DECtalk PC (big ISA card) synthesizer support" - ---help--- + help This is the Speakup driver for the DecTalk PC (full length ISA) synthesizer. You can say m to build it as @@ -127,7 +127,7 @@ config SPEAKUP_SYNTH_DECPC config SPEAKUP_SYNTH_DTLK tristate "DoubleTalk PC synthesizer support" depends on ISA || COMPILE_TEST - ---help--- + help This is the Speakup driver for the internal DoubleTalk PC synthesizer. You can say y to build it into the @@ -138,7 +138,7 @@ config SPEAKUP_SYNTH_DTLK config SPEAKUP_SYNTH_KEYPC tristate "Keynote Gold PC synthesizer support" depends on ISA || COMPILE_TEST - ---help--- + help This is the Speakup driver for the Keynote Gold PC synthesizer. You can say y to build it into the @@ -148,7 +148,7 @@ config SPEAKUP_SYNTH_KEYPC config SPEAKUP_SYNTH_LTLK tristate "DoubleTalk LT/LiteTalk synthesizer support" ----help--- +help This is the Speakup driver for the LiteTalk/DoubleTalk LT synthesizer. You can say y to build it into the @@ -158,7 +158,7 @@ config SPEAKUP_SYNTH_LTLK config SPEAKUP_SYNTH_SOFT tristate "Userspace software synthesizer support" - ---help--- + help This is the software synthesizer device node. It will register a device /dev/softsynth which midware programs @@ -169,7 +169,7 @@ config SPEAKUP_SYNTH_SOFT config SPEAKUP_SYNTH_SPKOUT tristate "Speak Out synthesizer support" - ---help--- + help This is the Speakup driver for the Speakout synthesizer. You can say y to build it into the kernel, or m to @@ -178,7 +178,7 @@ config SPEAKUP_SYNTH_SPKOUT config SPEAKUP_SYNTH_TXPRT tristate "Transport synthesizer support" - ---help--- + help This is the Speakup driver for the Transport synthesizer. You can say y to build it into the kernel, @@ -187,7 +187,7 @@ config SPEAKUP_SYNTH_TXPRT config SPEAKUP_SYNTH_DUMMY tristate "Dummy synthesizer driver (for testing)" - ---help--- + help This is a dummy Speakup driver for plugging a mere serial terminal. This is handy if you want to test speakup but -- cgit v1.2.3 From e062b6e572431106e06f7546de8dd31d027ea5cd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 30 Dec 2018 16:53:12 +0100 Subject: staging: rtl8192e: reduce indentation Delete tab aligning a statement with the right hand side of a preceding assignment rather than the left hand side. Found with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 843e874b8a06..b798cde0ce47 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -1049,9 +1049,9 @@ static int _rtl92e_wx_set_promisc_mode(struct net_device *dev, (bPromiscuousOn) ? (true) : (false); ieee->IntelPromiscuousModeInfo.bFilterSourceStationFrame = (bFilterSourceStationFrame) ? (true) : (false); - (bPromiscuousOn) ? - (rtllib_EnableIntelPromiscuousMode(dev, false)) : - (rtllib_DisableIntelPromiscuousMode(dev, false)); + (bPromiscuousOn) ? + (rtllib_EnableIntelPromiscuousMode(dev, false)) : + (rtllib_DisableIntelPromiscuousMode(dev, false)); netdev_info(dev, "=======>%s(), on = %d, filter src sta = %d\n", -- cgit v1.2.3 From 8f452bbb9a427420ed01993c3233df4e570f5238 Mon Sep 17 00:00:00 2001 From: William Mitchell Jr Date: Sat, 29 Dec 2018 22:14:12 -0500 Subject: staging: comedi: cb_pcimdas.c: fixed an alignment coding style issue Fixed a coding style issue. Signed-off-by: William Mitchell Jr Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/cb_pcimdas.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index 4e72a0778086..a9d052bfda38 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -252,9 +252,9 @@ static int cb_pcimdas_di_insn_bits(struct comedi_device *dev, } static int cb_pcimdas_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct cb_pcimdas_private *devpriv = dev->private; -- cgit v1.2.3 From 75f3da8958d03748b5d1d743d04f64d6f6993d5f Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Thu, 20 Dec 2018 18:14:50 +0100 Subject: staging: fsl-dpaa2: fix SPDX identifiers in header files Use the correct comment style for SPDX identifiers in header files. Reported by checkpatch. Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 2 +- drivers/staging/fsl-dpaa2/ethsw/dpsw.h | 2 +- drivers/staging/fsl-dpaa2/ethsw/ethsw.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h index da744f2b0ee6..14b974defa3a 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright 2014-2016 Freescale Semiconductor Inc. * Copyright 2017-2018 NXP diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h index db43fa3782b8..25635259ce44 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright 2014-2016 Freescale Semiconductor Inc. * Copyright 2017-2018 NXP diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h index 069c99bfba74..c48783680a05 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * DPAA2 Ethernet Switch declarations * -- cgit v1.2.3 From 73b69c01cc925d9c48e5b4f78e3d8b88c4e5b924 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Thu, 27 Dec 2018 13:35:53 -0600 Subject: staging: rts5208: Add a check for ms_read_extra_data In ms_copy_page, the function ms_read_extra_data may fail for many reasons. The fix adds a check similar to other invocation to return error upstream. Signed-off-by: Aditya Pakki Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts5208/ms.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c index e43f92080c20..1128eec3bd08 100644 --- a/drivers/staging/rts5208/ms.c +++ b/drivers/staging/rts5208/ms.c @@ -1665,7 +1665,10 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, return STATUS_FAIL; } - ms_read_extra_data(chip, old_blk, i, extra, MS_EXTRA_SIZE); + retval = ms_read_extra_data(chip, old_blk, i, extra, + MS_EXTRA_SIZE); + if (retval != STATUS_SUCCESS) + return STATUS_FAIL; retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6); -- cgit v1.2.3 From 5f98ddc9a7770c054a55bbfe925cddc8c8c30685 Mon Sep 17 00:00:00 2001 From: Himadri Pandya Date: Tue, 1 Jan 2019 06:43:19 -0800 Subject: staging: rtl8192e: rename Channel to channel style This patch fixes the checkpatch.pl warning: CHECK: Avoid CamelCase: Signed-off-by: Himadri Pandya Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/dot11d.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c index a1c096124683..687deac19796 100644 --- a/drivers/staging/rtl8192e/dot11d.c +++ b/drivers/staging/rtl8192e/dot11d.c @@ -15,7 +15,7 @@ #include "dot11d.h" struct channel_list { - u8 Channel[32]; + u8 channel[32]; u8 Len; }; @@ -66,11 +66,11 @@ void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee) memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); for (i = 0; i < ChannelPlan[channel_plan].Len; i++) { - if (ChannelPlan[channel_plan].Channel[i] < min_chan || - ChannelPlan[channel_plan].Channel[i] > max_chan) + if (ChannelPlan[channel_plan].channel[i] < min_chan || + ChannelPlan[channel_plan].channel[i] > max_chan) break; GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan - [channel_plan].Channel[i]] = 1; + [channel_plan].channel[i]] = 1; } } -- cgit v1.2.3 From 9a47dc5f7eb3ad9a7145f43e19a2bc19b1073bfc Mon Sep 17 00:00:00 2001 From: Prathamesh Deshpande Date: Mon, 24 Dec 2018 08:53:46 -0800 Subject: staging: wlan-ng: prism2fw.c: Fix "Possible unnecessary 'out of memory' message" checkpatch.pl warning" This patch removes unnecessary out of memory warning message from wlan-ng prism2fw.c file. Signed-off-by: Prathamesh Deshpande Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/prism2fw.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c index bb572b7fdfee..94800c007162 100644 --- a/drivers/staging/wlan-ng/prism2fw.c +++ b/drivers/staging/wlan-ng/prism2fw.c @@ -556,10 +556,9 @@ static int mkimage(struct imgchunk *clist, unsigned int *ccnt) /* Allocate buffer space for chunks */ for (i = 0; i < *ccnt; i++) { clist[i].data = kzalloc(clist[i].len, GFP_KERNEL); - if (!clist[i].data) { - pr_err("failed to allocate image space, exiting.\n"); + if (!clist[i].data) return 1; - } + pr_debug("chunk[%d]: addr=0x%06x len=%d\n", i, clist[i].addr, clist[i].len); } -- cgit v1.2.3 From a0e447b0c50240a90ab84b7126b3c06b0bab4adc Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Sun, 23 Dec 2018 01:42:49 +0900 Subject: clk: rockchip: fix frac settings of GPLL clock for rk3328 This patch fixes settings of GPLL frequency in fractional mode for rk3328. In this mode, FOUTVCO is calcurated by following formula: FOUTVCO = FREF * FBDIV / REFDIV + ((FREF * FRAC / REFDIV) >> 24) The problem is in FREF * FRAC >> 24 term. This result always lacks one from target value is specified by rate member. For example first itme of rk3328_pll_frac_rate originally has - rate : 1016064000 - refdiv: 3 - fbdiv : 127 - frac : 134217 - FREF * FBDIV / REFDIV = 1016000000 - (FREF * FRAC / REFDIV) >> 24 = 63999 Thus calculated rate is 1016063999. It seems wrong. If frac has 134218 (it is increased 1 from original value), second term is 64000. All other items have same situation. So this patch adds 1 to frac member in all items of rk3328_pll_frac_rate. Signed-off-by: Katsuhiro Suzuki Acked-by: Elaine Zhang Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index faa94adb2a37..65ab5c2f48b0 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -78,17 +78,17 @@ static struct rockchip_pll_rate_table rk3328_pll_rates[] = { static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = { /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ - RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217), + RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134218), /* vco = 1016064000 */ - RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088), + RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671089), /* vco = 983040000 */ - RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088), + RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671089), /* vco = 983040000 */ - RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088), + RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671089), /* vco = 860156000 */ - RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894), + RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797895), /* vco = 903168000 */ - RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329), + RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066330), /* vco = 819200000 */ { /* sentinel */ }, }; -- cgit v1.2.3 From 491b00ff699356a8dab10eb517a1b44205514c9e Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Sat, 29 Dec 2018 14:33:13 +0100 Subject: clk: rockchip: add CLK_SET_RATE_PARENT for rk3066 lcdc dclks Add CLK_SET_RATE_PARENT for both rk3066 lcdc dclk. Signed-off-by: Finley Xiao Signed-off-by: Johan Jonker Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3188.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 7ea20341e870..5ecf28854876 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -586,12 +586,12 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { COMPOSITE(0, "dclk_lcdc0_src", mux_pll_src_cpll_gpll_p, 0, RK2928_CLKSEL_CON(27), 0, 1, MFLAGS, 8, 8, DFLAGS, RK2928_CLKGATE_CON(3), 1, GFLAGS), - MUX(DCLK_LCDC0, "dclk_lcdc0", mux_rk3066_lcdc0_p, 0, + MUX(DCLK_LCDC0, "dclk_lcdc0", mux_rk3066_lcdc0_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(27), 4, 1, MFLAGS), COMPOSITE(0, "dclk_lcdc1_src", mux_pll_src_cpll_gpll_p, 0, RK2928_CLKSEL_CON(28), 0, 1, MFLAGS, 8, 8, DFLAGS, RK2928_CLKGATE_CON(3), 2, GFLAGS), - MUX(DCLK_LCDC1, "dclk_lcdc1", mux_rk3066_lcdc1_p, 0, + MUX(DCLK_LCDC1, "dclk_lcdc1", mux_rk3066_lcdc1_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(28), 4, 1, MFLAGS), COMPOSITE_NOMUX(0, "cif1_pre", "cif_src", 0, -- cgit v1.2.3 From 0ca1f90861b6d64386261096b42bfc81ce11948a Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Fri, 4 Jan 2019 12:34:08 +0100 Subject: staging: mt7621-pinctrl: use pinconf-generic for 'dt_node_to_map' and 'dt_free_map' Instead of reimplement afunction to do 'dt_node_to_map' task like 'rt2880_pinctrl_dt_node_to_map' make use of 'pinconf_generic_dt_node_to_map_all' generic function for this task. Also use its equivalent function for free which is 'pinconf_generic_dt_free_map'. Remove 'rt2880_pinctrl_dt_node_to_map' function which is not needed anymore. This decrease a bit driver LOC and make it more generic. To properly compile this changes 'GENERIC_PINCONF' option is selected with the driver in its Kconfig file. This also fix a problem with function 'rt2880_pinctrl_dt_node_to_map' which was calling internally 'pinctrl_utils_reserve_map' which expects 'num_maps' to be initialized. It does a memory allocation based on the value, and triggers the following warning if is not properly set: if (unlikely(order >= MAX_ORDER)) { WARN_ON_ONCE(!(gfp_mask & __GFP_NOWARN)); return NULL; } Generic function 'pinconf_generic_dt_node_to_map_all' initializes properly 'num_maps' to zero fixing the problem. Fixes: e12a1a6e087b ("staging: mt7621-pinctrl: refactor rt2880_pinctrl_dt_node_to_map function") Reported-by: NeilBrown Tested-by: NeilBrown Signed-off-by: Sergio Paracuellos Signed-off-by: Greg Kroah-Hartman --- drivers/staging/mt7621-pinctrl/Kconfig | 1 + drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c | 41 ++----------------------- 2 files changed, 4 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/mt7621-pinctrl/Kconfig b/drivers/staging/mt7621-pinctrl/Kconfig index 37cf9c3273be..fc3612711307 100644 --- a/drivers/staging/mt7621-pinctrl/Kconfig +++ b/drivers/staging/mt7621-pinctrl/Kconfig @@ -2,3 +2,4 @@ config PINCTRL_RT2880 bool "RT2800 pinctrl driver for RALINK/Mediatek SOCs" depends on RALINK select PINMUX + select GENERIC_PINCONF diff --git a/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c index aa98fbb17013..80e7067cfb79 100644 --- a/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c +++ b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -73,48 +74,12 @@ static int rt2880_get_group_pins(struct pinctrl_dev *pctrldev, return 0; } -static int rt2880_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrldev, - struct device_node *np_config, - struct pinctrl_map **map, - unsigned int *num_maps) -{ - struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); - struct property *prop; - const char *function_name, *group_name; - int ret; - int ngroups = 0; - unsigned int reserved_maps = 0; - - for_each_node_with_property(np_config, "group") - ngroups++; - - *map = NULL; - ret = pinctrl_utils_reserve_map(pctrldev, map, &reserved_maps, - num_maps, ngroups); - if (ret) { - dev_err(p->dev, "can't reserve map: %d\n", ret); - return ret; - } - - of_property_for_each_string(np_config, "group", prop, group_name) { - ret = pinctrl_utils_add_map_mux(pctrldev, map, &reserved_maps, - num_maps, group_name, - function_name); - if (ret) { - dev_err(p->dev, "can't add map: %d\n", ret); - return ret; - } - } - - return 0; -} - static const struct pinctrl_ops rt2880_pctrl_ops = { .get_groups_count = rt2880_get_group_count, .get_group_name = rt2880_get_group_name, .get_group_pins = rt2880_get_group_pins, - .dt_node_to_map = rt2880_pinctrl_dt_node_to_map, - .dt_free_map = pinctrl_utils_free_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinconf_generic_dt_free_map, }; static int rt2880_pmx_func_count(struct pinctrl_dev *pctrldev) -- cgit v1.2.3 From bd7c95d48854af2db899bc8b6966a0e9b9f5bf4e Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Fri, 4 Jan 2019 12:34:09 +0100 Subject: staging: mt7621-dts: use standard 'groups' instead of 'group' for pinctrl bindings Pinctrl generic functions looks for standard property 'groups' in DT to get data and use in the driver. Change all of them. Signed-off-by: Sergio Paracuellos Signed-off-by: Greg Kroah-Hartman --- drivers/staging/mt7621-dts/gbpc1.dts | 4 ++-- drivers/staging/mt7621-dts/mt7621.dtsi | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts index 6a1699ce9455..b73385540216 100644 --- a/drivers/staging/mt7621-dts/gbpc1.dts +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -136,8 +136,8 @@ &pinctrl { state_default: pinctrl0 { gpio { - ralink,group = "wdt", "rgmii2", "uart3"; - ralink,function = "gpio"; + groups = "wdt", "rgmii2", "uart3"; + function = "gpio"; }; }; }; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 71f069d59ad8..1cec0879e825 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -204,82 +204,82 @@ i2c_pins: i2c0 { i2c0 { - group = "i2c"; + groups = "i2c"; function = "i2c"; }; }; spi_pins: spi0 { spi0 { - group = "spi"; + groups = "spi"; function = "spi"; }; }; uart1_pins: uart1 { uart1 { - group = "uart1"; + groups = "uart1"; function = "uart1"; }; }; uart2_pins: uart2 { uart2 { - group = "uart2"; + groups = "uart2"; function = "uart2"; }; }; uart3_pins: uart3 { uart3 { - group = "uart3"; + groups = "uart3"; function = "uart3"; }; }; rgmii1_pins: rgmii1 { rgmii1 { - group = "rgmii1"; + groups = "rgmii1"; function = "rgmii1"; }; }; rgmii2_pins: rgmii2 { rgmii2 { - group = "rgmii2"; + groups = "rgmii2"; function = "rgmii2"; }; }; mdio_pins: mdio0 { mdio0 { - group = "mdio"; + groups = "mdio"; function = "mdio"; }; }; pcie_pins: pcie0 { pcie0 { - group = "pcie"; + groups = "pcie"; function = "pcie rst"; }; }; nand_pins: nand0 { spi-nand { - group = "spi"; + groups = "spi"; function = "nand1"; }; sdhci-nand { - group = "sdhci"; + groups = "sdhci"; function = "nand2"; }; }; sdhci_pins: sdhci0 { sdhci0 { - group = "sdhci"; + groups = "sdhci"; function = "sdhci"; }; }; -- cgit v1.2.3 From 00981d31d6dfd0c60a3447d046205bd615ed847c Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Fri, 4 Jan 2019 08:08:21 +0100 Subject: staging: mt7621-pci-phy: add new driver for phy part of mt7621-pci Phy part of the pci for this SoC can be handled using a generic phy driver. This commit extracts phy part of the mt7621-pci into a new 'mt7621-pci-phy' driver. Signed-off-by: Sergio Paracuellos Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/mt7621-pci-phy/Kconfig | 7 + drivers/staging/mt7621-pci-phy/Makefile | 1 + drivers/staging/mt7621-pci-phy/TODO | 4 + drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c | 387 ++++++++++++++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 drivers/staging/mt7621-pci-phy/Kconfig create mode 100644 drivers/staging/mt7621-pci-phy/Makefile create mode 100644 drivers/staging/mt7621-pci-phy/TODO create mode 100644 drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index e4f608815c05..4a3d6e00f7cb 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -104,6 +104,8 @@ source "drivers/staging/pi433/Kconfig" source "drivers/staging/mt7621-pci/Kconfig" +source "drivers/staging/mt7621-pci-phy/Kconfig" + source "drivers/staging/mt7621-pinctrl/Kconfig" source "drivers/staging/mt7621-spi/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 5868631e8f1b..413890dd5a14 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/ obj-$(CONFIG_PI433) += pi433/ obj-$(CONFIG_SOC_MT7621) += mt7621-pci/ +obj-$(CONFIG_SOC_MT7621) += mt7621-pci-phy/ obj-$(CONFIG_SOC_MT7621) += mt7621-pinctrl/ obj-$(CONFIG_SOC_MT7621) += mt7621-spi/ obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ diff --git a/drivers/staging/mt7621-pci-phy/Kconfig b/drivers/staging/mt7621-pci-phy/Kconfig new file mode 100644 index 000000000000..b9f6ab784ee8 --- /dev/null +++ b/drivers/staging/mt7621-pci-phy/Kconfig @@ -0,0 +1,7 @@ +config PCI_MT7621_PHY + tristate "MediaTek MT7621 PCI PHY Driver" + depends on RALINK && OF + select GENERIC_PHY + help + Say 'Y' here to add support for MediaTek MT7621 PCI PHY driver, + diff --git a/drivers/staging/mt7621-pci-phy/Makefile b/drivers/staging/mt7621-pci-phy/Makefile new file mode 100644 index 000000000000..2b82ccfc28c6 --- /dev/null +++ b/drivers/staging/mt7621-pci-phy/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SOC_MT7621) += pci-mt7621-phy.o diff --git a/drivers/staging/mt7621-pci-phy/TODO b/drivers/staging/mt7621-pci-phy/TODO new file mode 100644 index 000000000000..a255e8f753eb --- /dev/null +++ b/drivers/staging/mt7621-pci-phy/TODO @@ -0,0 +1,4 @@ + +- general code review and cleanup + +Cc: NeilBrown and Sergio Paracuellos diff --git a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c new file mode 100644 index 000000000000..3d16716cfebc --- /dev/null +++ b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mediatek MT7621 PCI PHY Driver + * Author: Sergio Paracuellos + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RALINK_CLKCFG1 0x30 +#define CHIP_REV_MT7621_E2 0x0101 + +#define PCIE_PORT_CLK_EN(x) BIT(24 + (x)) + +#define RG_PE1_PIPE_REG 0x02c +#define RG_PE1_PIPE_RST BIT(12) +#define RG_PE1_PIPE_CMD_FRC BIT(4) + +#define RG_P0_TO_P1_WIDTH 0x100 +#define RG_PE1_H_LCDDS_REG 0x49c +#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) +#define RG_PE1_H_LCDDS_PCW_VAL(x) ((0x7fffffff & (x)) << 0) + +#define RG_PE1_FRC_H_XTAL_REG 0x400 +#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) +#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) +#define RG_PE1_H_XTAL_TYPE_VAL(x) ((0x3 & (x)) << 9) + +#define RG_PE1_FRC_PHY_REG 0x000 +#define RG_PE1_FRC_PHY_EN BIT(4) +#define RG_PE1_PHY_EN BIT(5) + +#define RG_PE1_H_PLL_REG 0x490 +#define RG_PE1_H_PLL_BC GENMASK(23, 22) +#define RG_PE1_H_PLL_BC_VAL(x) ((0x3 & (x)) << 22) +#define RG_PE1_H_PLL_BP GENMASK(21, 18) +#define RG_PE1_H_PLL_BP_VAL(x) ((0xf & (x)) << 18) +#define RG_PE1_H_PLL_IR GENMASK(15, 12) +#define RG_PE1_H_PLL_IR_VAL(x) ((0xf & (x)) << 12) +#define RG_PE1_H_PLL_IC GENMASK(11, 8) +#define RG_PE1_H_PLL_IC_VAL(x) ((0xf & (x)) << 8) +#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) +#define RG_PE1_H_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6) +#define RG_PE1_PLL_DIVEN GENMASK(3, 1) +#define RG_PE1_PLL_DIVEN_VAL(x) ((0x7 & (x)) << 1) + +#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc +#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) +#define RG_PE1_H_PLL_FBKSEL_VAL(x) ((0x3 & (x)) << 4) + +#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 +#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) +#define RG_PE1_H_LCDDS_SSC_PRD_VAL(x) ((0xffff & (x)) << 0) + +#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 +#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) +#define RG_PE1_H_LCDDS_SSC_DELTA_VAL(x) ((0xfff & (x)) << 0) +#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) +#define RG_PE1_H_LCDDS_SSC_DELTA1_VAL(x) ((0xff & (x)) << 16) + +#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 +#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) + +#define RG_PE1_H_PLL_BR_REG 0x4ac +#define RG_PE1_H_PLL_BR GENMASK(18, 16) +#define RG_PE1_H_PLL_BR_VAL(x) ((0x7 & (x)) << 16) + +#define RG_PE1_MSTCKDIV_REG 0x414 +#define RG_PE1_MSTCKDIV GENMASK(7, 6) +#define RG_PE1_MSTCKDIV_VAL(x) ((0x3 & (x)) << 6) + +#define RG_PE1_FRC_MSTCKDIV BIT(5) + +/** + * struct mt7621_pci_phy_instance - Mt7621 Pcie PHY device + * @phy: pointer to the kernel PHY device + * @port_base: base register + * @index: internal ID to identify the Mt7621 PCIe PHY + */ +struct mt7621_pci_phy_instance { + struct phy *phy; + void __iomem *port_base; + u32 index; +}; + +/** + * struct mt7621_pci_phy - Mt7621 Pcie PHY core + * @dev: pointer to device + * @phys: pointer to Mt7621 PHY device + * @nphys: number of PHY devices for this core + */ +struct mt7621_pci_phy { + struct device *dev; + struct mt7621_pci_phy_instance **phys; + int nphys; +}; + +static inline u32 phy_read(struct mt7621_pci_phy_instance *instance, u32 reg) +{ + return readl(instance->port_base + reg); +} + +static inline void phy_write(struct mt7621_pci_phy_instance *instance, + u32 val, u32 reg) +{ + writel(val, instance->port_base + reg); +} + +static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy, + struct mt7621_pci_phy_instance *instance) +{ + u32 offset = (instance->index != 1) ? + RG_PE1_PIPE_REG : RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH; + u32 reg; + + reg = phy_read(instance, offset); + reg &= ~(RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC); + reg |= (RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC); + phy_write(instance, reg, offset); +} + +static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy, + struct mt7621_pci_phy_instance *instance) +{ + struct device *dev = phy->dev; + u32 reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0); + u32 offset; + u32 val; + + reg = (reg >> 6) & 0x7; + /* Set PCIe Port PHY to disable SSC */ + /* Debug Xtal Type */ + val = phy_read(instance, RG_PE1_FRC_H_XTAL_REG); + val &= ~(RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE); + val |= RG_PE1_FRC_H_XTAL_TYPE; + val |= RG_PE1_H_XTAL_TYPE_VAL(0x00); + phy_write(instance, val, RG_PE1_FRC_H_XTAL_REG); + + /* disable port */ + offset = (instance->index != 1) ? + RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH; + val = phy_read(instance, offset); + val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN); + val |= RG_PE1_FRC_PHY_EN; + phy_write(instance, val, offset); + + /* Set Pre-divider ratio (for host mode) */ + val = phy_read(instance, RG_PE1_H_PLL_REG); + val &= ~(RG_PE1_H_PLL_PREDIV); + + if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */ + val |= RG_PE1_H_PLL_PREDIV_VAL(0x01); + phy_write(instance, val, RG_PE1_H_PLL_REG); + dev_info(dev, "Xtal is 40MHz\n"); + } else { /* 25MHz | 20MHz Xtal */ + val |= RG_PE1_H_PLL_PREDIV_VAL(0x00); + phy_write(instance, val, RG_PE1_H_PLL_REG); + if (reg >= 6) { + dev_info(dev, "Xtal is 25MHz\n"); + + /* Select feedback clock */ + val = phy_read(instance, RG_PE1_H_PLL_FBKSEL_REG); + val &= ~(RG_PE1_H_PLL_FBKSEL); + val |= RG_PE1_H_PLL_FBKSEL_VAL(0x01); + phy_write(instance, val, RG_PE1_H_PLL_FBKSEL_REG); + + /* DDS NCPO PCW (for host mode) */ + val = phy_read(instance, RG_PE1_H_LCDDS_SSC_PRD_REG); + val &= ~(RG_PE1_H_LCDDS_SSC_PRD); + val |= RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000); + phy_write(instance, val, RG_PE1_H_LCDDS_SSC_PRD_REG); + + /* DDS SSC dither period control */ + val = phy_read(instance, RG_PE1_H_LCDDS_SSC_PRD_REG); + val &= ~(RG_PE1_H_LCDDS_SSC_PRD); + val |= RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d); + phy_write(instance, val, RG_PE1_H_LCDDS_SSC_PRD_REG); + + /* DDS SSC dither amplitude control */ + val = phy_read(instance, RG_PE1_H_LCDDS_SSC_DELTA_REG); + val &= ~(RG_PE1_H_LCDDS_SSC_DELTA | + RG_PE1_H_LCDDS_SSC_DELTA1); + val |= RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a); + val |= RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a); + phy_write(instance, val, RG_PE1_H_LCDDS_SSC_DELTA_REG); + } else { + dev_info(dev, "Xtal is 20MHz\n"); + } + } + + /* DDS clock inversion */ + val = phy_read(instance, RG_PE1_LCDDS_CLK_PH_INV_REG); + val &= ~(RG_PE1_LCDDS_CLK_PH_INV); + val |= RG_PE1_LCDDS_CLK_PH_INV; + phy_write(instance, val, RG_PE1_LCDDS_CLK_PH_INV_REG); + + /* Set PLL bits */ + val = phy_read(instance, RG_PE1_H_PLL_REG); + val &= ~(RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR | + RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN); + val |= RG_PE1_H_PLL_BC_VAL(0x02); + val |= RG_PE1_H_PLL_BP_VAL(0x06); + val |= RG_PE1_H_PLL_IR_VAL(0x02); + val |= RG_PE1_H_PLL_IC_VAL(0x01); + val |= RG_PE1_PLL_DIVEN_VAL(0x02); + phy_write(instance, val, RG_PE1_H_PLL_REG); + + val = phy_read(instance, RG_PE1_H_PLL_BR_REG); + val &= ~(RG_PE1_H_PLL_BR); + val |= RG_PE1_H_PLL_BR_VAL(0x00); + phy_write(instance, val, RG_PE1_H_PLL_BR_REG); + + if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */ + /* set force mode enable of da_pe1_mstckdiv */ + val = phy_read(instance, RG_PE1_MSTCKDIV_REG); + val &= ~(RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV); + val |= (RG_PE1_MSTCKDIV_VAL(0x01) | RG_PE1_FRC_MSTCKDIV); + phy_write(instance, val, RG_PE1_MSTCKDIV_REG); + } +} + +static int mt7621_pci_phy_init(struct phy *phy) +{ + struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy); + struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent); + u32 chip_rev_id = rt_sysc_r32(SYSC_REG_CHIP_REV); + + if ((chip_rev_id & 0xFFFF) == CHIP_REV_MT7621_E2) + mt7621_bypass_pipe_rst(mphy, instance); + + mt7621_set_phy_for_ssc(mphy, instance); + + return 0; +} + +static int mt7621_pci_phy_power_on(struct phy *phy) +{ + struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy); + u32 offset = (instance->index != 1) ? + RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH; + u32 val; + + /* Enable PHY and disable force mode */ + val = phy_read(instance, offset); + val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN); + val |= (RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN); + phy_write(instance, val, offset); + + return 0; +} + +static int mt7621_pci_phy_power_off(struct phy *phy) +{ + struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy); + u32 offset = (instance->index != 1) ? + RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH; + u32 val; + + /* Disable PHY */ + val = phy_read(instance, offset); + val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN); + val |= RG_PE1_FRC_PHY_EN; + phy_write(instance, val, offset); + + return 0; +} + +static int mt7621_pci_phy_exit(struct phy *phy) +{ + struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy); + + rt_sysc_m32(PCIE_PORT_CLK_EN(instance->index), 0, RALINK_CLKCFG1); + + return 0; +} + +static const struct phy_ops mt7621_pci_phy_ops = { + .init = mt7621_pci_phy_init, + .exit = mt7621_pci_phy_exit, + .power_on = mt7621_pci_phy_power_on, + .power_off = mt7621_pci_phy_power_off, + .owner = THIS_MODULE, +}; + +static int mt7621_pci_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child_np; + struct phy_provider *provider; + struct mt7621_pci_phy *phy; + struct resource res; + int port, ret; + void __iomem *port_base; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->nphys = of_get_child_count(np); + phy->phys = devm_kcalloc(dev, phy->nphys, + sizeof(*phy->phys), GFP_KERNEL); + if (!phy->phys) + return -ENOMEM; + + phy->dev = dev; + platform_set_drvdata(pdev, phy); + + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(dev, "failed to get address resource(id-%d)\n", port); + return ret; + } + + port_base = devm_ioremap_resource(dev, &res); + if (IS_ERR(port_base)) { + dev_err(dev, "failed to remap phy regs\n"); + return PTR_ERR(port_base); + } + + port = 0; + for_each_child_of_node(np, child_np) { + struct mt7621_pci_phy_instance *instance; + struct phy *pphy; + + instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); + if (!instance) { + ret = -ENOMEM; + goto put_child; + } + + phy->phys[port] = instance; + + pphy = devm_phy_create(dev, child_np, &mt7621_pci_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy\n"); + ret = PTR_ERR(phy); + goto put_child; + } + + instance->port_base = port_base; + instance->phy = pphy; + instance->index = port; + phy_set_drvdata(pphy, instance); + port++; + } + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); + +put_child: + of_node_put(child_np); + return ret; +} + +static const struct of_device_id mt7621_pci_phy_ids[] = { + { .compatible = "mediatek,mt7621-pci-phy" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt7621_pci_ids); + +static struct platform_driver mt7621_pci_phy_driver = { + .probe = mt7621_pci_phy_probe, + .driver = { + .name = "mt7621-pci-phy", + .of_match_table = of_match_ptr(mt7621_pci_phy_ids), + }, +}; + +static int __init mt7621_pci_phy_drv_init(void) +{ + return platform_driver_register(&mt7621_pci_phy_driver); +} + +arch_initcall(mt7621_pci_phy_drv_init); + +MODULE_AUTHOR("Sergio Paracuellos "); +MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 61f9bde6ea578f5baa1662c97365f7b36fc790fa Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Fri, 4 Jan 2019 08:08:22 +0100 Subject: staging: mt7621-pci: handle phy using new generic phy 'pci-mt7621-phy' driver Phy part of this driver has been moved to a new 'pci-mt7621-phy' driver. Change code to use kernel's generic phy API removing also no more need moved code. Signed-off-by: Sergio Paracuellos Signed-off-by: Greg Kroah-Hartman --- drivers/staging/mt7621-pci/pci-mt7621.c | 250 ++++---------------------------- 1 file changed, 32 insertions(+), 218 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 31310b6fb7db..8db94fdbdd6d 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -95,76 +96,12 @@ #define RALINK_PCI_IO_MAP_BASE 0x1e160000 #define MEMORY_BASE 0x0 -/* pcie phy related macros */ -#define RALINK_PCIEPHY_P0P1_CTL_OFFSET 0x9000 -#define RALINK_PCIEPHY_P2_CTL_OFFSET 0xA000 - -#define RG_P0_TO_P1_WIDTH 0x100 - -#define RG_PE1_PIPE_REG 0x02c -#define RG_PE1_PIPE_RST BIT(12) -#define RG_PE1_PIPE_CMD_FRC BIT(4) - -#define RG_PE1_H_LCDDS_REG 0x49c -#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) -#define RG_PE1_H_LCDDS_PCW_VAL(x) ((0x7fffffff & (x)) << 0) - -#define RG_PE1_FRC_H_XTAL_REG 0x400 -#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) -#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) -#define RG_PE1_H_XTAL_TYPE_VAL(x) ((0x3 & (x)) << 9) - -#define RG_PE1_FRC_PHY_REG 0x000 -#define RG_PE1_FRC_PHY_EN BIT(4) -#define RG_PE1_PHY_EN BIT(5) - -#define RG_PE1_H_PLL_REG 0x490 -#define RG_PE1_H_PLL_BC GENMASK(23, 22) -#define RG_PE1_H_PLL_BC_VAL(x) ((0x3 & (x)) << 22) -#define RG_PE1_H_PLL_BP GENMASK(21, 18) -#define RG_PE1_H_PLL_BP_VAL(x) ((0xf & (x)) << 18) -#define RG_PE1_H_PLL_IR GENMASK(15, 12) -#define RG_PE1_H_PLL_IR_VAL(x) ((0xf & (x)) << 12) -#define RG_PE1_H_PLL_IC GENMASK(11, 8) -#define RG_PE1_H_PLL_IC_VAL(x) ((0xf & (x)) << 8) -#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) -#define RG_PE1_H_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6) -#define RG_PE1_PLL_DIVEN GENMASK(3, 1) -#define RG_PE1_PLL_DIVEN_VAL(x) ((0x7 & (x)) << 1) - -#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc -#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) -#define RG_PE1_H_PLL_FBKSEL_VAL(x) ((0x3 & (x)) << 4) - -#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 -#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) -#define RG_PE1_H_LCDDS_SSC_PRD_VAL(x) ((0xffff & (x)) << 0) - -#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 -#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) -#define RG_PE1_H_LCDDS_SSC_DELTA_VAL(x) ((0xfff & (x)) << 0) -#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) -#define RG_PE1_H_LCDDS_SSC_DELTA1_VAL(x) ((0xff & (x)) << 16) - -#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 -#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) - -#define RG_PE1_H_PLL_BR_REG 0x4ac -#define RG_PE1_H_PLL_BR GENMASK(18, 16) -#define RG_PE1_H_PLL_BR_VAL(x) ((0x7 & (x)) << 16) - -#define RG_PE1_MSTCKDIV_REG 0x414 -#define RG_PE1_MSTCKDIV GENMASK(7, 6) -#define RG_PE1_MSTCKDIV_VAL(x) ((0x3 & (x)) << 6) - -#define RG_PE1_FRC_MSTCKDIV BIT(5) - /** * struct mt7621_pcie_port - PCIe port information * @base: I/O mapped register base * @list: port list * @pcie: pointer to PCIe host info - * @phy_reg_offset: offset to related phy registers + * @phy: pointer to PHY control block * @pcie_rst: pointer to port reset control * @slot: port slot * @enabled: indicates if port is enabled @@ -173,7 +110,7 @@ struct mt7621_pcie_port { void __iomem *base; struct list_head list; struct mt7621_pcie *pcie; - u32 phy_reg_offset; + struct phy *phy; struct reset_control *pcie_rst; u32 slot; bool enabled; @@ -265,150 +202,6 @@ static void write_config(struct mt7621_pcie *pcie, unsigned int dev, pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA); } -static void bypass_pipe_rst(struct mt7621_pcie_port *port) -{ - struct mt7621_pcie *pcie = port->pcie; - u32 phy_offset = port->phy_reg_offset; - u32 offset = (port->slot != 1) ? - phy_offset + RG_PE1_PIPE_REG : - phy_offset + RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH; - u32 reg = pcie_read(pcie, offset); - - reg &= ~(RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC); - reg |= (RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC); - pcie_write(pcie, reg, offset); -} - -static void set_phy_for_ssc(struct mt7621_pcie_port *port) -{ - struct mt7621_pcie *pcie = port->pcie; - struct device *dev = pcie->dev; - u32 phy_offset = port->phy_reg_offset; - u32 reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0); - u32 offset; - u32 val; - - reg = (reg >> 6) & 0x7; - /* Set PCIe Port PHY to disable SSC */ - /* Debug Xtal Type */ - offset = phy_offset + RG_PE1_FRC_H_XTAL_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE); - val |= RG_PE1_FRC_H_XTAL_TYPE; - val |= RG_PE1_H_XTAL_TYPE_VAL(0x00); - pcie_write(pcie, val, offset); - - /* disable port */ - offset = (port->slot != 1) ? - phy_offset + RG_PE1_FRC_PHY_REG : - phy_offset + RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN); - val |= RG_PE1_FRC_PHY_EN; - pcie_write(pcie, val, offset); - - /* Set Pre-divider ratio (for host mode) */ - offset = phy_offset + RG_PE1_H_PLL_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_H_PLL_PREDIV); - - if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */ - val |= RG_PE1_H_PLL_PREDIV_VAL(0x01); - pcie_write(pcie, val, offset); - dev_info(dev, "Xtal is 40MHz\n"); - } else { /* 25MHz | 20MHz Xtal */ - val |= RG_PE1_H_PLL_PREDIV_VAL(0x00); - pcie_write(pcie, val, offset); - if (reg >= 6) { - dev_info(dev, "Xtal is 25MHz\n"); - - /* Select feedback clock */ - offset = phy_offset + RG_PE1_H_PLL_FBKSEL_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_H_PLL_FBKSEL); - val |= RG_PE1_H_PLL_FBKSEL_VAL(0x01); - pcie_write(pcie, val, offset); - - /* DDS NCPO PCW (for host mode) */ - offset = phy_offset + RG_PE1_H_LCDDS_SSC_PRD_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_H_LCDDS_SSC_PRD); - val |= RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000); - pcie_write(pcie, val, offset); - - /* DDS SSC dither period control */ - offset = phy_offset + RG_PE1_H_LCDDS_SSC_PRD_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_H_LCDDS_SSC_PRD); - val |= RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d); - pcie_write(pcie, val, offset); - - /* DDS SSC dither amplitude control */ - offset = phy_offset + RG_PE1_H_LCDDS_SSC_DELTA_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_H_LCDDS_SSC_DELTA | - RG_PE1_H_LCDDS_SSC_DELTA1); - val |= RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a); - val |= RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a); - pcie_write(pcie, val, offset); - } else { - dev_info(dev, "Xtal is 20MHz\n"); - } - } - - /* DDS clock inversion */ - offset = phy_offset + RG_PE1_LCDDS_CLK_PH_INV_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_LCDDS_CLK_PH_INV); - val |= RG_PE1_LCDDS_CLK_PH_INV; - pcie_write(pcie, val, offset); - - /* Set PLL bits */ - offset = phy_offset + RG_PE1_H_PLL_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR | - RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN); - val |= RG_PE1_H_PLL_BC_VAL(0x02); - val |= RG_PE1_H_PLL_BP_VAL(0x06); - val |= RG_PE1_H_PLL_IR_VAL(0x02); - val |= RG_PE1_H_PLL_IC_VAL(0x01); - val |= RG_PE1_PLL_DIVEN_VAL(0x02); - pcie_write(pcie, val, offset); - - offset = phy_offset + RG_PE1_H_PLL_BR_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_H_PLL_BR); - val |= RG_PE1_H_PLL_BR_VAL(0x00); - pcie_write(pcie, val, offset); - - if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */ - /* set force mode enable of da_pe1_mstckdiv */ - offset = phy_offset + RG_PE1_MSTCKDIV_REG; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV); - val |= (RG_PE1_MSTCKDIV_VAL(0x01) | RG_PE1_FRC_MSTCKDIV); - pcie_write(pcie, val, offset); - } - - /* Enable PHY and disable force mode */ - offset = (port->slot != 1) ? - phy_offset + RG_PE1_FRC_PHY_REG : - phy_offset + RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH; - val = pcie_read(pcie, offset); - val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN); - val |= (RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN); - pcie_write(pcie, val, offset); -} - -static void mt7621_enable_phy(struct mt7621_pcie_port *port) -{ - u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID); - - if ((chip_rev_id & 0xFFFF) == CHIP_REV_MT7621_E2) - bypass_pipe_rst(port); - set_phy_for_ssc(port); -} - static inline void mt7621_control_assert(struct mt7621_pcie_port *port) { u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID); @@ -510,7 +303,7 @@ static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie, struct device *dev = pcie->dev; struct device_node *pnode = dev->of_node; struct resource regs; - char name[6]; + char name[10]; int err; port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); @@ -534,11 +327,13 @@ static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie, return PTR_ERR(port->pcie_rst); } + snprintf(name, sizeof(name), "pcie-phy%d", slot); + port->phy = devm_phy_get(dev, name); + if (IS_ERR(port->phy)) + return PTR_ERR(port->phy); + port->slot = slot; port->pcie = pcie; - port->phy_reg_offset = (slot != 2) ? - RALINK_PCIEPHY_P0P1_CTL_OFFSET : - RALINK_PCIEPHY_P2_CTL_OFFSET; INIT_LIST_HEAD(&port->list); list_add_tail(&port->list, &pcie->ports); @@ -588,6 +383,7 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port) struct device *dev = pcie->dev; u32 slot = port->slot; u32 val = 0; + int err; /* * Any MT7621 Ralink pcie controller that doesn't have 0x0101 at @@ -598,18 +394,36 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port) val = read_config(pcie, slot, PCIE_FTS_NUM); dev_info(dev, "Port %d N_FTS = %x\n", (unsigned int)val, slot); + err = phy_init(port->phy); + if (err) { + dev_err(dev, "failed to initialize port%d phy\n", slot); + goto err_phy_init; + } + + err = phy_power_on(port->phy); + if (err) { + dev_err(dev, "failed to power on port%d phy\n", slot); + goto err_phy_on; + } + if ((pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) == 0) { dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n", slot); mt7621_control_assert(port); - rt_sysc_m32(PCIE_PORT_CLK_EN(slot), 0, RALINK_CLKCFG1); port->enabled = false; - } else { - port->enabled = true; + err = -ENODEV; + goto err_no_link_up; } - mt7621_enable_phy(port); + port->enabled = true; return 0; + +err_no_link_up: + phy_power_off(port->phy); +err_phy_on: + phy_exit(port->phy); +err_phy_init: + return err; } static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie) -- cgit v1.2.3 From 06184ba5a33a16f1772857d2cf97f7f14c8018c7 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Fri, 4 Jan 2019 08:08:23 +0100 Subject: staging: mt7621-dts: add pci-phy related bindings to board's device tree New driver for pci phy has been added, as well as. pci driver has been changed to use kernel's generic PHY API. Add related PCI PHY bindings accordly. Signed-off-by: Sergio Paracuellos Signed-off-by: Greg Kroah-Hartman --- drivers/staging/mt7621-dts/mt7621.dtsi | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 1cec0879e825..f0c51622eca1 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -424,6 +424,8 @@ reset-names = "pcie0", "pcie1", "pcie2"; clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>; clock-names = "pcie0", "pcie1", "pcie2"; + phys = <&pcie0_port>, <&pcie1_port>, <&pcie2_port>; + phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2"; pcie@0,0 { reg = <0x0000 0 0 0 0>; @@ -449,4 +451,33 @@ bus-range = <0x00 0xff>; }; }; + + pcie0_phy: pcie-phy@1a149000 { + compatible = "mediatek,mt7621-pci-phy"; + reg = <0x1a149000 0x0700>; + #address-cells = <1>; + #size-cells = <0>; + + pcie0_port: pcie-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + pcie1_port: pcie-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; + + pcie1_phy: pcie-phy@1a14a000 { + compatible = "mediatek,mt7621-pci-phy"; + reg = <0x1a14a000 0x0700>; + #address-cells = <1>; + #size-cells = <0>; + + pcie2_port: pcie-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + }; }; -- cgit v1.2.3 From 9e2ddbdd9218bf0e465d19daecdd053052ffd79c Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Fri, 4 Jan 2019 08:08:24 +0100 Subject: staging: mt7621-pci-phy: dt-bindings: add bindings for Mediatek MT7621 Pcie PHY Add bindings documentation for PCie PHY of Mediatek MT7621. This file will be moved into its appropiate documentation bindings'place when this driver is mainlined. CC: Device Tree mailing list Signed-off-by: Sergio Paracuellos Signed-off-by: Greg Kroah-Hartman --- .../mt7621-pci-phy/mediatek,mt7621-pci-phy.txt | 54 ++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.txt (limited to 'drivers') diff --git a/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.txt b/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.txt new file mode 100644 index 000000000000..33a8a698bdd0 --- /dev/null +++ b/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.txt @@ -0,0 +1,54 @@ +Mediatek Mt7621 PCIe PHY + +Required properties: +- compatible: must be "mediatek,mt7621-pci-phy" +- reg: base address and length of the PCIe PHY block +- #address-cells: must be 1 +- #size-cells: must be 0 + +Each PCIe PHY should be represented by a child node + +Required properties For the child node: +- reg: the PHY ID +0 - PCIe RC 0 +1 - PCIe RC 1 +- #phy-cells: must be 0 + +Example: + pcie0_phy: pcie-phy@1a149000 { + compatible = "mediatek,mt7621-pci-phy"; + reg = <0x1a149000 0x0700>; + #address-cells = <1>; + #size-cells = <0>; + + pcie0_port: pcie-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + pcie1_port: pcie-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; + + pcie1_phy: pcie-phy@1a14a000 { + compatible = "mediatek,mt7621-pci-phy"; + reg = <0x1a14a000 0x0700>; + #address-cells = <1>; + #size-cells = <0>; + + pcie2_port: pcie-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + }; + + /* users of the PCIe phy */ + + pcie: pcie@1e140000 { + ... + ... + phys = <&pcie0_port>, <&pcie1_port>, <&pcie2_port>; + phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2"; + }; \ No newline at end of file -- cgit v1.2.3 From 037e9edf9d058f68ec33ec518e41c63949f84a0c Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Fri, 4 Jan 2019 22:50:12 +0100 Subject: staging: comedi: fix typo Fix spelling mistake: "lenghth" -> "length" Signed-off-by: Matteo Croce Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxfast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index e18c0723b760..0d54f394dbd2 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -61,7 +61,7 @@ #define USBDUXFASTSUB_CPUCS 0xE600 /* - * max lenghth of the transfer-buffer for software upload + * max length of the transfer-buffer for software upload */ #define TB_LEN 0x2000 -- cgit v1.2.3 From 045ee2d0d0757b02f7a8897c26bed3dc127aa564 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 15:30:47 -0600 Subject: staging: mt7621-dma: Use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/staging/mt7621-dma/ralink-gdma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/mt7621-dma/ralink-gdma.c b/drivers/staging/mt7621-dma/ralink-gdma.c index 792a63bd55d4..d78042eba6dd 100644 --- a/drivers/staging/mt7621-dma/ralink-gdma.c +++ b/drivers/staging/mt7621-dma/ralink-gdma.c @@ -821,9 +821,9 @@ static int gdma_dma_probe(struct platform_device *pdev) return -EINVAL; data = (struct gdma_data *) match->data; - dma_dev = devm_kzalloc(&pdev->dev, sizeof(*dma_dev) + - (sizeof(struct gdma_dmaengine_chan) * data->chancnt), - GFP_KERNEL); + dma_dev = devm_kzalloc(&pdev->dev, + struct_size(dma_dev, chan, data->chancnt), + GFP_KERNEL); if (!dma_dev) { dev_err(&pdev->dev, "alloc dma device failed\n"); return -EINVAL; -- cgit v1.2.3 From c8c2702409430a6a2fd928e857f15773aaafcc99 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Sat, 5 Jan 2019 08:14:41 -0600 Subject: Staging: rts5208: Fix error handling on rtsx_send_cmd In sd_execute_write_data, the rtsx_send_cmd could fail with ETIMEDOUT or EIO. The fix adds a check to handle these failures. Signed-off-by: Aditya Pakki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts5208/sd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c index 2c47ae613ea1..c256a2398651 100644 --- a/drivers/staging/rts5208/sd.c +++ b/drivers/staging/rts5208/sd.c @@ -4437,7 +4437,12 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) rtsx_init_cmd(chip); rtsx_add_cmd(chip, CHECK_REG_CMD, 0xFD30, 0x02, 0x02); - rtsx_send_cmd(chip, SD_CARD, 250); + retval = rtsx_send_cmd(chip, SD_CARD, 250); + if (retval < 0) { + write_err = true; + rtsx_clear_sd_error(chip); + goto sd_execute_write_cmd_failed; + } retval = sd_update_lock_status(chip); if (retval != STATUS_SUCCESS) { -- cgit v1.2.3 From 87fe9ae84d7ba61df1f272e26df174e73b15cd74 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Jan 2019 13:07:35 +0200 Subject: dmaengine: dw: Add missed multi-block support for iDMA 32-bit Intel integrated DMA 32-bit support multi-block transfers. Add missed setting to the platform data. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw/pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 7778ed705a1a..313ba10c6224 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -25,6 +25,7 @@ static struct dw_dma_platform_data mrfld_pdata = { .block_size = 131071, .nr_masters = 1, .data_width = {4}, + .multi_block = {1, 1, 1, 1, 1, 1, 1, 1}, }; static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) -- cgit v1.2.3 From d7dba6be0f31ae61f5f3296aa130f45d57d30f74 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Jan 2019 13:07:36 +0200 Subject: dmaengine: dw: Remove misleading is_private property The commit a9ddb575d6d6 ("dmaengine: dw_dmac: Enhance device tree support") introduces is_private property in uncertain understanding what does it mean. First of all, documentation defines DMA_PRIVATE capability as Documentation/crypto/async-tx-api.txt: The DMA_PRIVATE capability flag is used to tag dma devices that should not be used by the general-purpose allocator. It can be set at initialization time if it is known that a channel will always be private. Alternatively, it is set when dma_request_channel() finds an unused "public" channel. A couple caveats to note when implementing a driver and consumer: 1/ Once a channel has been privately allocated it will no longer be considered by the general-purpose allocator even after a call to dma_release_channel(). 2/ Since capabilities are specified at the device level a dma_device with multiple channels will either have all channels public, or all channels private. Documentation/driver-api/dmaengine/provider.rst: - DMA_PRIVATE The devices only supports slave transfers, and as such isn't available for async transfers. The capability had been introduced by the commit 59b5ec21446b ("dmaengine: introduce dma_request_channel and private channels") and some code didn't changed from that times ever. Taking into consideration above and the fact that on all known platforms Synopsys DesignWare DMA engine is attached to serve slave transfers, the DMA_PRIVATE capability must be enabled for this device unconditionally. Otherwise, as rightfully noticed in drivers/dma/at_xdmac.c: /* * Without DMA_PRIVATE the driver is not able to allocate more than * one channel, second allocation fails in private_candidate. */ because of of a caveats mentioned in above documentation excerpts. So, remove conditional around DMA_PRIVATE followed by removal leftovers. If someone wonders, DMA_PRIVATE can be not used if and only if the all channels of the DMA controller are supposed to serve memory-to-memory like operations. For example, EP93xx has two controllers, one of which can only perform memory-to-memory transfers Note, this change doesn't affect dmatest to be able to test such controllers. Cc: Greg Kroah-Hartman (maintainer:SERIAL DRIVERS) Cc: Dan Williams Signed-off-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Signed-off-by: Vinod Koul --- drivers/dma/dw/core.c | 4 +--- drivers/dma/dw/pci.c | 1 - drivers/dma/dw/platform.c | 3 --- drivers/tty/serial/8250/8250_lpss.c | 1 - 4 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index dc053e62f894..e25503986680 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1227,7 +1227,6 @@ int dw_dma_probe(struct dw_dma_chip *chip) pdata->block_size = dma_readl(dw, MAX_BLK_SIZE); /* Fill platform data with the default values */ - pdata->is_private = true; pdata->is_memcpy = true; pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING; pdata->chan_priority = CHAN_PRIORITY_ASCENDING; @@ -1340,8 +1339,7 @@ int dw_dma_probe(struct dw_dma_chip *chip) /* Set capabilities */ dma_cap_set(DMA_SLAVE, dw->dma.cap_mask); - if (pdata->is_private) - dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask); + dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask); if (pdata->is_memcpy) dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask); diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 313ba10c6224..570498faadc3 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -17,7 +17,6 @@ static struct dw_dma_platform_data mrfld_pdata = { .nr_channels = 8, - .is_private = true, .is_memcpy = true, .is_idma32 = true, .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 31ff8113c3de..6dd8cd1820c1 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -128,9 +128,6 @@ dw_dma_parse_dt(struct platform_device *pdev) pdata->nr_masters = nr_masters; pdata->nr_channels = nr_channels; - if (of_property_read_bool(np, "is_private")) - pdata->is_private = true; - /* * All known devices, which use DT for configuration, support * memory-to-memory transfers. So enable it by default. diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 98dbc796353f..53ca9ba6ab4b 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -153,7 +153,6 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) #ifdef CONFIG_SERIAL_8250_DMA static const struct dw_dma_platform_data qrk_serial_dma_pdata = { .nr_channels = 2, - .is_private = true, .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, .chan_priority = CHAN_PRIORITY_ASCENDING, .block_size = 4095, -- cgit v1.2.3 From 078165779608873e7b6eae1316a39c73af9f3edc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Jan 2019 13:07:37 +0200 Subject: dmaengine: dw: Remove unused internal property All known devices, which use DT for configuration, support memory-to-memory transfers. So enable it by default. The rest two cases, i.e. Intel Quark and PPC460ex, instantiate DMA driver and use its channels exclusively for hardware, which means there is no available channel for any other purposes anyway. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw/core.c | 4 +--- drivers/dma/dw/pci.c | 1 - drivers/dma/dw/platform.c | 6 ------ 3 files changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index e25503986680..4982e443869c 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1227,7 +1227,6 @@ int dw_dma_probe(struct dw_dma_chip *chip) pdata->block_size = dma_readl(dw, MAX_BLK_SIZE); /* Fill platform data with the default values */ - pdata->is_memcpy = true; pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING; pdata->chan_priority = CHAN_PRIORITY_ASCENDING; } else if (chip->pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) { @@ -1340,8 +1339,7 @@ int dw_dma_probe(struct dw_dma_chip *chip) /* Set capabilities */ dma_cap_set(DMA_SLAVE, dw->dma.cap_mask); dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask); - if (pdata->is_memcpy) - dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask); + dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask); dw->dma.dev = chip->dev; dw->dma.device_alloc_chan_resources = dwc_alloc_chan_resources; diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 570498faadc3..66d98d7ccad0 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -17,7 +17,6 @@ static struct dw_dma_platform_data mrfld_pdata = { .nr_channels = 8, - .is_memcpy = true, .is_idma32 = true, .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, .chan_priority = CHAN_PRIORITY_ASCENDING, diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 6dd8cd1820c1..58fc1ba02a1e 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -128,12 +128,6 @@ dw_dma_parse_dt(struct platform_device *pdev) pdata->nr_masters = nr_masters; pdata->nr_channels = nr_channels; - /* - * All known devices, which use DT for configuration, support - * memory-to-memory transfers. So enable it by default. - */ - pdata->is_memcpy = true; - if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) pdata->chan_allocation_order = (unsigned char)tmp; -- cgit v1.2.3 From 69da8be90d5e85e60b5377c47384154b9dabf592 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Jan 2019 13:07:38 +0200 Subject: dmaengine: dw: Split DW and iDMA 32-bit operations Here is a kinda big refactoring that should have been done in the first place, when Intel iDMA 32-bit support appeared. It splits operations which are different to Synopsys DesignWare and Intel iDMA 32-bit controllers. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw/Makefile | 2 +- drivers/dma/dw/core.c | 190 +++++++++------------------------------------- drivers/dma/dw/dw.c | 112 +++++++++++++++++++++++++++ drivers/dma/dw/idma32.c | 138 +++++++++++++++++++++++++++++++++ drivers/dma/dw/internal.h | 10 ++- drivers/dma/dw/pci.c | 45 +++++++---- drivers/dma/dw/platform.c | 8 +- drivers/dma/dw/regs.h | 13 ++++ 8 files changed, 339 insertions(+), 179 deletions(-) create mode 100644 drivers/dma/dw/dw.c create mode 100644 drivers/dma/dw/idma32.c (limited to 'drivers') diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile index 2b949c2e4504..63ed895c09aa 100644 --- a/drivers/dma/dw/Makefile +++ b/drivers/dma/dw/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DW_DMAC_CORE) += dw_dmac_core.o -dw_dmac_core-objs := core.o +dw_dmac_core-objs := core.o dw.o idma32.o obj-$(CONFIG_DW_DMAC) += dw_dmac.o dw_dmac-objs := platform.o diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 4982e443869c..8a581d86ea8d 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -138,44 +138,6 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc) dwc->descs_allocated--; } -static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc) -{ - u32 cfghi = 0; - u32 cfglo = 0; - - /* 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(dwc->dws.dst_id & 0xf); - cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf); - - /* Request line extension (2 bits) */ - cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3); - cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3); - - channel_writel(dwc, CFG_LO, cfglo); - channel_writel(dwc, CFG_HI, cfghi); -} - -static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc) -{ - struct dw_dma *dw = to_dw_dma(dwc->chan.device); - u32 cfghi = DWC_CFGH_FIFO_MODE; - u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); - bool hs_polarity = dwc->dws.hs_polarity; - - cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id); - cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id); - cfghi |= DWC_CFGH_PROTCTL(dw->pdata->protctl); - - /* Set polarity of handshake interface */ - cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0; - - channel_writel(dwc, CFG_LO, cfglo); - channel_writel(dwc, CFG_HI, cfghi); -} - static void dwc_initialize(struct dw_dma_chan *dwc) { struct dw_dma *dw = to_dw_dma(dwc->chan.device); @@ -183,10 +145,7 @@ static void dwc_initialize(struct dw_dma_chan *dwc) if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags)) return; - if (dw->pdata->is_idma32) - dwc_initialize_chan_idma32(dwc); - else - dwc_initialize_chan_dw(dwc); + dw->initialize_chan(dwc); /* Enable interrupts */ channel_set_bit(dw, MASK.XFER, dwc->mask); @@ -215,37 +174,6 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc) cpu_relax(); } -static u32 bytes2block(struct dw_dma_chan *dwc, size_t bytes, - unsigned int width, size_t *len) -{ - struct dw_dma *dw = to_dw_dma(dwc->chan.device); - u32 block; - - /* Always in bytes for iDMA 32-bit */ - if (dw->pdata->is_idma32) - width = 0; - - if ((bytes >> width) > dwc->block_size) { - block = dwc->block_size; - *len = block << width; - } else { - block = bytes >> width; - *len = bytes; - } - - return block; -} - -static size_t block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width) -{ - struct dw_dma *dw = to_dw_dma(dwc->chan.device); - - if (dw->pdata->is_idma32) - return IDMA32C_CTLH_BLOCK_TS(block); - - return DWC_CTLH_BLOCK_TS(block) << width; -} - /*----------------------------------------------------------------------*/ /* Perform single block transfer */ @@ -391,10 +319,11 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc) /* Returns how many bytes were already received from source */ static inline u32 dwc_get_sent(struct dw_dma_chan *dwc) { + struct dw_dma *dw = to_dw_dma(dwc->chan.device); u32 ctlhi = channel_readl(dwc, CTL_HI); u32 ctllo = channel_readl(dwc, CTL_LO); - return block2bytes(dwc, ctlhi, ctllo >> 4 & 7); + return dw->block2bytes(dwc, ctlhi, ctllo >> 4 & 7); } static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) @@ -651,7 +580,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, unsigned int src_width; unsigned int dst_width; unsigned int data_width = dw->pdata->data_width[m_master]; - u32 ctllo; + u32 ctllo, ctlhi; u8 lms = DWC_LLP_LMS(m_master); dev_vdbg(chan2dev(chan), @@ -680,10 +609,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, if (!desc) goto err_desc_get; + ctlhi = dw->bytes2block(dwc, len - offset, src_width, &xfer_count); + lli_write(desc, sar, src + offset); lli_write(desc, dar, dest + offset); lli_write(desc, ctllo, ctllo); - lli_write(desc, ctlhi, bytes2block(dwc, len - offset, src_width, &xfer_count)); + lli_write(desc, ctlhi, ctlhi); desc->len = xfer_count; if (!first) { @@ -721,7 +652,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct dma_slave_config *sconfig = &dwc->dma_sconfig; struct dw_desc *prev; struct dw_desc *first; - u32 ctllo; + u32 ctllo, ctlhi; u8 m_master = dwc->dws.m_master; u8 lms = DWC_LLP_LMS(m_master); dma_addr_t reg; @@ -768,9 +699,11 @@ slave_sg_todev_fill_desc: if (!desc) goto err_desc_get; + ctlhi = dw->bytes2block(dwc, len, mem_width, &dlen); + lli_write(desc, sar, mem); lli_write(desc, dar, reg); - lli_write(desc, ctlhi, bytes2block(dwc, len, mem_width, &dlen)); + lli_write(desc, ctlhi, ctlhi); lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width)); desc->len = dlen; @@ -814,9 +747,11 @@ slave_sg_fromdev_fill_desc: if (!desc) goto err_desc_get; + ctlhi = dw->bytes2block(dwc, len, reg_width, &dlen); + lli_write(desc, sar, reg); lli_write(desc, dar, mem); - lli_write(desc, ctlhi, bytes2block(dwc, len, reg_width, &dlen)); + lli_write(desc, ctlhi, ctlhi); mem_width = __ffs(data_width | mem | dlen); lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width)); desc->len = dlen; @@ -876,22 +811,12 @@ EXPORT_SYMBOL_GPL(dw_dma_filter); static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dma_slave_config *sc = &dwc->dma_sconfig; struct dw_dma *dw = to_dw_dma(chan->device); - /* - * Fix sconfig's burst size according to dw_dmac. We need to convert - * them as: - * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. - * - * NOTE: burst size 2 is not supported by DesignWare controller. - * iDMA 32-bit supports it. - */ - u32 s = dw->pdata->is_idma32 ? 1 : 2; memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); - sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0; - sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0; + dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst); + dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst); return 0; } @@ -900,16 +825,9 @@ static void dwc_chan_pause(struct dw_dma_chan *dwc, bool drain) { struct dw_dma *dw = to_dw_dma(dwc->chan.device); unsigned int count = 20; /* timeout iterations */ - u32 cfglo; - cfglo = channel_readl(dwc, CFG_LO); - if (dw->pdata->is_idma32) { - if (drain) - cfglo |= IDMA32C_CFGL_CH_DRAIN; - else - cfglo &= ~IDMA32C_CFGL_CH_DRAIN; - } - channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); + dw->suspend_chan(dwc, drain); + while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--) udelay(2); @@ -1058,33 +976,7 @@ static void dwc_issue_pending(struct dma_chan *chan) /*----------------------------------------------------------------------*/ -/* - * Program FIFO size of channels. - * - * By default full FIFO (512 bytes) is assigned to channel 0. Here we - * slice FIFO on equal parts between channels. - */ -static void idma32_fifo_partition(struct dw_dma *dw) -{ - u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) | - IDMA32C_FP_UPDATE; - u64 fifo_partition = 0; - - if (!dw->pdata->is_idma32) - return; - - /* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */ - fifo_partition |= value << 0; - - /* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */ - fifo_partition |= value << 32; - - /* Program FIFO Partition registers - 64 bytes per channel */ - idma32_writeq(dw, FIFO_PARTITION1, fifo_partition); - idma32_writeq(dw, FIFO_PARTITION0, fifo_partition); -} - -static void dw_dma_off(struct dw_dma *dw) +void do_dw_dma_off(struct dw_dma *dw) { unsigned int i; @@ -1103,7 +995,7 @@ static void dw_dma_off(struct dw_dma *dw) clear_bit(DW_DMA_IS_INITIALIZED, &dw->chan[i].flags); } -static void dw_dma_on(struct dw_dma *dw) +void do_dw_dma_on(struct dw_dma *dw) { dma_writel(dw, CFG, DW_CFG_DMA_EN); } @@ -1139,7 +1031,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) /* Enable controller here if needed */ if (!dw->in_use) - dw_dma_on(dw); + do_dw_dma_on(dw); dw->in_use |= dwc->mask; return 0; @@ -1177,30 +1069,25 @@ static void dwc_free_chan_resources(struct dma_chan *chan) /* Disable controller in case it was a last user */ dw->in_use &= ~dwc->mask; if (!dw->in_use) - dw_dma_off(dw); + do_dw_dma_off(dw); dev_vdbg(chan2dev(chan), "%s: done\n", __func__); } -int dw_dma_probe(struct dw_dma_chip *chip) +int do_dma_probe(struct dw_dma_chip *chip) { + struct dw_dma *dw = chip->dw; struct dw_dma_platform_data *pdata; - struct dw_dma *dw; bool autocfg = false; unsigned int dw_params; unsigned int i; int err; - dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL); - if (!dw) - return -ENOMEM; - dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL); if (!dw->pdata) return -ENOMEM; dw->regs = chip->regs; - chip->dw = dw; pm_runtime_get_sync(chip->dev); @@ -1250,15 +1137,10 @@ int dw_dma_probe(struct dw_dma_chip *chip) dw->all_chan_mask = (1 << pdata->nr_channels) - 1; /* Force dma off, just in case */ - dw_dma_off(dw); - - idma32_fifo_partition(dw); + dw->disable(dw); /* Device and instance ID for IRQ and DMA pool */ - if (pdata->is_idma32) - snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", chip->id); - else - snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", chip->id); + dw->set_device_name(dw, chip->id); /* Create a pool of consistent memory blocks for hardware descriptors */ dw->desc_pool = dmam_pool_create(dw->name, chip->dev, @@ -1380,16 +1262,15 @@ err_pdata: pm_runtime_put_sync_suspend(chip->dev); return err; } -EXPORT_SYMBOL_GPL(dw_dma_probe); -int dw_dma_remove(struct dw_dma_chip *chip) +int do_dma_remove(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; struct dw_dma_chan *dwc, *_dwc; pm_runtime_get_sync(chip->dev); - dw_dma_off(dw); + do_dw_dma_off(dw); dma_async_device_unregister(&dw->dma); free_irq(chip->irq, dw); @@ -1404,27 +1285,24 @@ int dw_dma_remove(struct dw_dma_chip *chip) pm_runtime_put_sync_suspend(chip->dev); return 0; } -EXPORT_SYMBOL_GPL(dw_dma_remove); -int dw_dma_disable(struct dw_dma_chip *chip) +int do_dw_dma_disable(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; - dw_dma_off(dw); + dw->disable(dw); return 0; } -EXPORT_SYMBOL_GPL(dw_dma_disable); +EXPORT_SYMBOL_GPL(do_dw_dma_disable); -int dw_dma_enable(struct dw_dma_chip *chip) +int do_dw_dma_enable(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; - idma32_fifo_partition(dw); - - dw_dma_on(dw); + dw->enable(dw); return 0; } -EXPORT_SYMBOL_GPL(dw_dma_enable); +EXPORT_SYMBOL_GPL(do_dw_dma_enable); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver"); diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c new file mode 100644 index 000000000000..977aa28bf81d --- /dev/null +++ b/drivers/dma/dw/dw.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2007-2008 Atmel Corporation +// Copyright (C) 2010-2011 ST Microelectronics +// Copyright (C) 2013,2018 Intel Corporation + +#include +#include +#include +#include + +#include "internal.h" + +static void dw_dma_initialize_chan(struct dw_dma_chan *dwc) +{ + struct dw_dma *dw = to_dw_dma(dwc->chan.device); + u32 cfghi = DWC_CFGH_FIFO_MODE; + u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); + bool hs_polarity = dwc->dws.hs_polarity; + + cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id); + cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id); + cfghi |= DWC_CFGH_PROTCTL(dw->pdata->protctl); + + /* Set polarity of handshake interface */ + cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0; + + channel_writel(dwc, CFG_LO, cfglo); + channel_writel(dwc, CFG_HI, cfghi); +} + +static void dw_dma_suspend_chan(struct dw_dma_chan *dwc, bool drain) +{ + u32 cfglo = channel_readl(dwc, CFG_LO); + + channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); +} + +static u32 dw_dma_bytes2block(struct dw_dma_chan *dwc, + size_t bytes, unsigned int width, size_t *len) +{ + u32 block; + + if ((bytes >> width) > dwc->block_size) { + block = dwc->block_size; + *len = dwc->block_size << width; + } else { + block = bytes >> width; + *len = bytes; + } + + return block; +} + +static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width) +{ + return DWC_CTLH_BLOCK_TS(block) << width; +} + +static void dw_dma_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst) +{ + /* + * Fix burst size according to dw_dmac. We need to convert them as: + * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. + */ + *maxburst = *maxburst > 1 ? fls(*maxburst) - 2 : 0; +} + +static void dw_dma_set_device_name(struct dw_dma *dw, int id) +{ + snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", id); +} + +static void dw_dma_disable(struct dw_dma *dw) +{ + do_dw_dma_off(dw); +} + +static void dw_dma_enable(struct dw_dma *dw) +{ + do_dw_dma_on(dw); +} + +int dw_dma_probe(struct dw_dma_chip *chip) +{ + struct dw_dma *dw; + + dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL); + if (!dw) + return -ENOMEM; + + /* Channel operations */ + dw->initialize_chan = dw_dma_initialize_chan; + dw->suspend_chan = dw_dma_suspend_chan; + dw->encode_maxburst = dw_dma_encode_maxburst; + dw->bytes2block = dw_dma_bytes2block; + dw->block2bytes = dw_dma_block2bytes; + + /* Device operations */ + dw->set_device_name = dw_dma_set_device_name; + dw->disable = dw_dma_disable; + dw->enable = dw_dma_enable; + + chip->dw = dw; + return do_dma_probe(chip); +} +EXPORT_SYMBOL_GPL(dw_dma_probe); + +int dw_dma_remove(struct dw_dma_chip *chip) +{ + return do_dma_remove(chip); +} +EXPORT_SYMBOL_GPL(dw_dma_remove); diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c new file mode 100644 index 000000000000..8707830f39ad --- /dev/null +++ b/drivers/dma/dw/idma32.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2013,2018 Intel Corporation + +#include +#include +#include +#include + +#include "internal.h" + +static void idma32_initialize_chan(struct dw_dma_chan *dwc) +{ + u32 cfghi = 0; + u32 cfglo = 0; + + /* 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(dwc->dws.dst_id & 0xf); + cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf); + + /* Request line extension (2 bits) */ + cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3); + cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3); + + channel_writel(dwc, CFG_LO, cfglo); + channel_writel(dwc, CFG_HI, cfghi); +} + +static void idma32_suspend_chan(struct dw_dma_chan *dwc, bool drain) +{ + u32 cfglo = channel_readl(dwc, CFG_LO); + + if (drain) + cfglo |= IDMA32C_CFGL_CH_DRAIN; + else + cfglo &= ~IDMA32C_CFGL_CH_DRAIN; + + channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); +} + +static u32 idma32_bytes2block(struct dw_dma_chan *dwc, + size_t bytes, unsigned int width, size_t *len) +{ + u32 block; + + if (bytes > dwc->block_size) { + block = dwc->block_size; + *len = dwc->block_size; + } else { + block = bytes; + *len = bytes; + } + + return block; +} + +static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width) +{ + return IDMA32C_CTLH_BLOCK_TS(block); +} + +static void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst) +{ + *maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0; +} + +static void idma32_set_device_name(struct dw_dma *dw, int id) +{ + snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", id); +} + +/* + * Program FIFO size of channels. + * + * By default full FIFO (512 bytes) is assigned to channel 0. Here we + * slice FIFO on equal parts between channels. + */ +static void idma32_fifo_partition(struct dw_dma *dw) +{ + u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) | + IDMA32C_FP_UPDATE; + u64 fifo_partition = 0; + + /* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */ + fifo_partition |= value << 0; + + /* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */ + fifo_partition |= value << 32; + + /* Program FIFO Partition registers - 64 bytes per channel */ + idma32_writeq(dw, FIFO_PARTITION1, fifo_partition); + idma32_writeq(dw, FIFO_PARTITION0, fifo_partition); +} + +static void idma32_disable(struct dw_dma *dw) +{ + do_dw_dma_off(dw); + idma32_fifo_partition(dw); +} + +static void idma32_enable(struct dw_dma *dw) +{ + idma32_fifo_partition(dw); + do_dw_dma_on(dw); +} + +int idma32_dma_probe(struct dw_dma_chip *chip) +{ + struct dw_dma *dw; + + dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL); + if (!dw) + return -ENOMEM; + + /* Channel operations */ + dw->initialize_chan = idma32_initialize_chan; + dw->suspend_chan = idma32_suspend_chan; + dw->encode_maxburst = idma32_encode_maxburst; + dw->bytes2block = idma32_bytes2block; + dw->block2bytes = idma32_block2bytes; + + /* Device operations */ + dw->set_device_name = idma32_set_device_name; + dw->disable = idma32_disable; + dw->enable = idma32_enable; + + chip->dw = dw; + return do_dma_probe(chip); +} +EXPORT_SYMBOL_GPL(idma32_dma_probe); + +int idma32_dma_remove(struct dw_dma_chip *chip) +{ + return do_dma_remove(chip); +} +EXPORT_SYMBOL_GPL(idma32_dma_remove); diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 41439732ff6b..fdcac21ea665 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -15,8 +15,14 @@ #include "regs.h" -int dw_dma_disable(struct dw_dma_chip *chip); -int dw_dma_enable(struct dw_dma_chip *chip); +int do_dma_probe(struct dw_dma_chip *chip); +int do_dma_remove(struct dw_dma_chip *chip); + +void do_dw_dma_on(struct dw_dma *dw); +void do_dw_dma_off(struct dw_dma *dw); + +int do_dw_dma_disable(struct dw_dma_chip *chip); +int do_dw_dma_enable(struct dw_dma_chip *chip); extern bool dw_dma_filter(struct dma_chan *chan, void *param); diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 66d98d7ccad0..e9ba25b4f950 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -15,9 +15,17 @@ #include "internal.h" -static struct dw_dma_platform_data mrfld_pdata = { +struct dw_dma_pci_data { + const struct dw_dma_platform_data *pdata; + int (*probe)(struct dw_dma_chip *chip); +}; + +static const struct dw_dma_pci_data dw_pci_data = { + .probe = dw_dma_probe, +}; + +static const struct dw_dma_platform_data idma32_pdata = { .nr_channels = 8, - .is_idma32 = true, .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, .chan_priority = CHAN_PRIORITY_ASCENDING, .block_size = 131071, @@ -26,9 +34,14 @@ static struct dw_dma_platform_data mrfld_pdata = { .multi_block = {1, 1, 1, 1, 1, 1, 1, 1}, }; +static const struct dw_dma_pci_data idma32_pci_data = { + .pdata = &idma32_pdata, + .probe = idma32_dma_probe, +}; + static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) { - const struct dw_dma_platform_data *pdata = (void *)pid->driver_data; + const struct dw_dma_pci_data *data = (void *)pid->driver_data; struct dw_dma_chip *chip; int ret; @@ -61,9 +74,9 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) chip->id = pdev->devfn; chip->regs = pcim_iomap_table(pdev)[0]; chip->irq = pdev->irq; - chip->pdata = pdata; + chip->pdata = data->pdata; - ret = dw_dma_probe(chip); + ret = data->probe(chip); if (ret) return ret; @@ -89,7 +102,7 @@ static int dw_pci_suspend_late(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct dw_dma_chip *chip = pci_get_drvdata(pci); - return dw_dma_disable(chip); + return do_dw_dma_disable(chip); }; static int dw_pci_resume_early(struct device *dev) @@ -97,7 +110,7 @@ static int dw_pci_resume_early(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct dw_dma_chip *chip = pci_get_drvdata(pci); - return dw_dma_enable(chip); + return do_dw_dma_enable(chip); }; #endif /* CONFIG_PM_SLEEP */ @@ -108,24 +121,24 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = { static const struct pci_device_id dw_pci_id_table[] = { /* Medfield (GPDMA) */ - { PCI_VDEVICE(INTEL, 0x0827) }, + { PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_data }, /* BayTrail */ - { PCI_VDEVICE(INTEL, 0x0f06) }, - { PCI_VDEVICE(INTEL, 0x0f40) }, + { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_data }, - /* Merrifield iDMA 32-bit (GPDMA) */ - { PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&mrfld_pdata }, + /* Merrifield */ + { PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_pci_data }, /* Braswell */ - { PCI_VDEVICE(INTEL, 0x2286) }, - { PCI_VDEVICE(INTEL, 0x22c0) }, + { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data }, /* Haswell */ - { PCI_VDEVICE(INTEL, 0x9c60) }, + { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data }, /* Broadwell */ - { PCI_VDEVICE(INTEL, 0x9ce0) }, + { PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_pci_data }, { } }; diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 58fc1ba02a1e..d5196c97e4f4 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -255,7 +255,7 @@ static void dw_shutdown(struct platform_device *pdev) struct dw_dma_chip *chip = platform_get_drvdata(pdev); /* - * We have to call dw_dma_disable() to stop any ongoing transfer. On + * We have to call do_dw_dma_disable() to stop any ongoing transfer. On * some platforms we can't do that since DMA device is powered off. * Moreover we have no possibility to check if the platform is affected * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put() @@ -264,7 +264,7 @@ static void dw_shutdown(struct platform_device *pdev) * used by the driver. */ pm_runtime_get_sync(chip->dev); - dw_dma_disable(chip); + do_dw_dma_disable(chip); pm_runtime_put_sync_suspend(chip->dev); clk_disable_unprepare(chip->clk); @@ -294,7 +294,7 @@ static int dw_suspend_late(struct device *dev) { struct dw_dma_chip *chip = dev_get_drvdata(dev); - dw_dma_disable(chip); + do_dw_dma_disable(chip); clk_disable_unprepare(chip->clk); return 0; @@ -309,7 +309,7 @@ static int dw_resume_early(struct device *dev) if (ret) return ret; - return dw_dma_enable(chip); + return do_dw_dma_enable(chip); } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 646c9c960c07..66aa8b227248 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -312,6 +312,19 @@ struct dw_dma { u8 all_chan_mask; u8 in_use; + /* Channel operations */ + void (*initialize_chan)(struct dw_dma_chan *dwc); + void (*suspend_chan)(struct dw_dma_chan *dwc, bool drain); + void (*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst); + u32 (*bytes2block)(struct dw_dma_chan *dwc, size_t bytes, + unsigned int width, size_t *len); + size_t (*block2bytes)(struct dw_dma_chan *dwc, u32 block, u32 width); + + /* Device operations */ + void (*set_device_name)(struct dw_dma *dw, int id); + void (*disable)(struct dw_dma *dw); + void (*enable)(struct dw_dma *dw); + /* platform data */ struct dw_dma_platform_data *pdata; }; -- cgit v1.2.3 From 91f0ff883e9ae654503fc62c588eefc8558e457f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Jan 2019 13:07:39 +0200 Subject: dmaengine: dw: Reset DRAIN bit when resume the channel For Intel iDMA 32-bit the channel can be drained on a suspend. We need to reset the bit on the resume to return a status quo. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw/core.c | 10 +++++----- drivers/dma/dw/dw.c | 8 ++++++++ drivers/dma/dw/idma32.c | 13 +++++++++++-- drivers/dma/dw/regs.h | 1 + 4 files changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 8a581d86ea8d..6a23203e601d 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -846,11 +846,11 @@ static int dwc_pause(struct dma_chan *chan) return 0; } -static inline void dwc_chan_resume(struct dw_dma_chan *dwc) +static inline void dwc_chan_resume(struct dw_dma_chan *dwc, bool drain) { - u32 cfglo = channel_readl(dwc, CFG_LO); + struct dw_dma *dw = to_dw_dma(dwc->chan.device); - channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP); + dw->resume_chan(dwc, drain); clear_bit(DW_DMA_IS_PAUSED, &dwc->flags); } @@ -863,7 +863,7 @@ static int dwc_resume(struct dma_chan *chan) spin_lock_irqsave(&dwc->lock, flags); if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags)) - dwc_chan_resume(dwc); + dwc_chan_resume(dwc, false); spin_unlock_irqrestore(&dwc->lock, flags); @@ -886,7 +886,7 @@ static int dwc_terminate_all(struct dma_chan *chan) dwc_chan_disable(dw, dwc); - dwc_chan_resume(dwc); + dwc_chan_resume(dwc, true); /* active_list entries will end up before queued entries */ list_splice_init(&dwc->queue, &list); diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c index 977aa28bf81d..156088f768f2 100644 --- a/drivers/dma/dw/dw.c +++ b/drivers/dma/dw/dw.c @@ -35,6 +35,13 @@ static void dw_dma_suspend_chan(struct dw_dma_chan *dwc, bool drain) channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); } +static void dw_dma_resume_chan(struct dw_dma_chan *dwc, bool drain) +{ + u32 cfglo = channel_readl(dwc, CFG_LO); + + channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP); +} + static u32 dw_dma_bytes2block(struct dw_dma_chan *dwc, size_t bytes, unsigned int width, size_t *len) { @@ -91,6 +98,7 @@ int dw_dma_probe(struct dw_dma_chip *chip) /* Channel operations */ dw->initialize_chan = dw_dma_initialize_chan; dw->suspend_chan = dw_dma_suspend_chan; + dw->resume_chan = dw_dma_resume_chan; dw->encode_maxburst = dw_dma_encode_maxburst; dw->bytes2block = dw_dma_bytes2block; dw->block2bytes = dw_dma_block2bytes; diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c index 8707830f39ad..cd23b9238333 100644 --- a/drivers/dma/dw/idma32.c +++ b/drivers/dma/dw/idma32.c @@ -34,12 +34,20 @@ static void idma32_suspend_chan(struct dw_dma_chan *dwc, bool drain) if (drain) cfglo |= IDMA32C_CFGL_CH_DRAIN; - else - cfglo &= ~IDMA32C_CFGL_CH_DRAIN; channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); } +static void idma32_resume_chan(struct dw_dma_chan *dwc, bool drain) +{ + u32 cfglo = channel_readl(dwc, CFG_LO); + + if (drain) + cfglo &= ~IDMA32C_CFGL_CH_DRAIN; + + channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP); +} + static u32 idma32_bytes2block(struct dw_dma_chan *dwc, size_t bytes, unsigned int width, size_t *len) { @@ -117,6 +125,7 @@ int idma32_dma_probe(struct dw_dma_chip *chip) /* Channel operations */ dw->initialize_chan = idma32_initialize_chan; dw->suspend_chan = idma32_suspend_chan; + dw->resume_chan = idma32_resume_chan; dw->encode_maxburst = idma32_encode_maxburst; dw->bytes2block = idma32_bytes2block; dw->block2bytes = idma32_block2bytes; diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 66aa8b227248..6cf299facf45 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -315,6 +315,7 @@ struct dw_dma { /* Channel operations */ void (*initialize_chan)(struct dw_dma_chan *dwc); void (*suspend_chan)(struct dw_dma_chan *dwc, bool drain); + void (*resume_chan)(struct dw_dma_chan *dwc, bool drain); void (*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst); u32 (*bytes2block)(struct dw_dma_chan *dwc, size_t bytes, unsigned int width, size_t *len); -- cgit v1.2.3 From 934891b0a16c55716de9cdd6cefc82cc2b75eb4a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Jan 2019 13:07:40 +0200 Subject: dmaengine: dw: Don't pollute CTL_LO on iDMA 32-bit Intel iDMA 32-bit doesn't have a concept of bus masters and thus there is no need to setup any kind of masters in the CTL_LO register. Moreover, the burst size for memory-to-memory transfer is not what is says, we need to have a corrected list of possible sizes. Note, that the size of 8 items, each of that up to 4 bytes, is chosen because of maximum of 1/2 FIFO, which is 64 bytes on Intel Merrifield. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw/core.c | 31 +++++-------------------------- drivers/dma/dw/dw.c | 18 ++++++++++++++++++ drivers/dma/dw/idma32.c | 13 +++++++++++++ drivers/dma/dw/regs.h | 11 +++++++++++ 4 files changed, 47 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 6a23203e601d..b7e4dab28f8a 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -37,27 +37,6 @@ * support descriptor writeback. */ -#define DWC_DEFAULT_CTLLO(_chan) ({ \ - struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \ - struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \ - bool _is_slave = is_slave_direction(_dwc->direction); \ - u8 _smsize = _is_slave ? _sconfig->src_maxburst : \ - DW_DMA_MSIZE_16; \ - u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \ - DW_DMA_MSIZE_16; \ - u8 _dms = (_dwc->direction == DMA_MEM_TO_DEV) ? \ - _dwc->dws.p_master : _dwc->dws.m_master; \ - u8 _sms = (_dwc->direction == DMA_DEV_TO_MEM) ? \ - _dwc->dws.p_master : _dwc->dws.m_master; \ - \ - (DWC_CTLL_DST_MSIZE(_dmsize) \ - | DWC_CTLL_SRC_MSIZE(_smsize) \ - | DWC_CTLL_LLP_D_EN \ - | DWC_CTLL_LLP_S_EN \ - | DWC_CTLL_DMS(_dms) \ - | DWC_CTLL_SMS(_sms)); \ - }) - /* The set of bus widths supported by the DMA controller */ #define DW_DMA_BUSWIDTHS \ BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \ @@ -596,7 +575,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, src_width = dst_width = __ffs(data_width | src | dest | len); - ctllo = DWC_DEFAULT_CTLLO(chan) + ctllo = dw->prepare_ctllo(dwc) | DWC_CTLL_DST_WIDTH(dst_width) | DWC_CTLL_SRC_WIDTH(src_width) | DWC_CTLL_DST_INC @@ -676,10 +655,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, case DMA_MEM_TO_DEV: reg_width = __ffs(sconfig->dst_addr_width); reg = sconfig->dst_addr; - ctllo = (DWC_DEFAULT_CTLLO(chan) + ctllo = dw->prepare_ctllo(dwc) | DWC_CTLL_DST_WIDTH(reg_width) | DWC_CTLL_DST_FIX - | DWC_CTLL_SRC_INC); + | DWC_CTLL_SRC_INC; ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) : DWC_CTLL_FC(DW_DMA_FC_D_M2P); @@ -726,10 +705,10 @@ slave_sg_todev_fill_desc: case DMA_DEV_TO_MEM: reg_width = __ffs(sconfig->src_addr_width); reg = sconfig->src_addr; - ctllo = (DWC_DEFAULT_CTLLO(chan) + ctllo = dw->prepare_ctllo(dwc) | DWC_CTLL_SRC_WIDTH(reg_width) | DWC_CTLL_DST_INC - | DWC_CTLL_SRC_FIX); + | DWC_CTLL_SRC_FIX; ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) : DWC_CTLL_FC(DW_DMA_FC_D_P2M); diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c index 156088f768f2..7a085b3c1854 100644 --- a/drivers/dma/dw/dw.c +++ b/drivers/dma/dw/dw.c @@ -4,6 +4,7 @@ // Copyright (C) 2013,2018 Intel Corporation #include +#include #include #include #include @@ -63,6 +64,22 @@ static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width) return DWC_CTLH_BLOCK_TS(block) << width; } +static u32 dw_dma_prepare_ctllo(struct dw_dma_chan *dwc) +{ + struct dma_slave_config *sconfig = &dwc->dma_sconfig; + bool is_slave = is_slave_direction(dwc->direction); + u8 smsize = is_slave ? sconfig->src_maxburst : DW_DMA_MSIZE_16; + u8 dmsize = is_slave ? sconfig->dst_maxburst : DW_DMA_MSIZE_16; + u8 p_master = dwc->dws.p_master; + u8 m_master = dwc->dws.m_master; + u8 dms = (dwc->direction == DMA_MEM_TO_DEV) ? p_master : m_master; + u8 sms = (dwc->direction == DMA_DEV_TO_MEM) ? p_master : m_master; + + return DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN | + DWC_CTLL_DST_MSIZE(dmsize) | DWC_CTLL_SRC_MSIZE(smsize) | + DWC_CTLL_DMS(dms) | DWC_CTLL_SMS(sms); +} + static void dw_dma_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst) { /* @@ -99,6 +116,7 @@ int dw_dma_probe(struct dw_dma_chip *chip) dw->initialize_chan = dw_dma_initialize_chan; dw->suspend_chan = dw_dma_suspend_chan; dw->resume_chan = dw_dma_resume_chan; + dw->prepare_ctllo = dw_dma_prepare_ctllo; dw->encode_maxburst = dw_dma_encode_maxburst; dw->bytes2block = dw_dma_bytes2block; dw->block2bytes = dw_dma_block2bytes; diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c index cd23b9238333..f00657308811 100644 --- a/drivers/dma/dw/idma32.c +++ b/drivers/dma/dw/idma32.c @@ -2,6 +2,7 @@ // Copyright (C) 2013,2018 Intel Corporation #include +#include #include #include #include @@ -69,6 +70,17 @@ static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width) return IDMA32C_CTLH_BLOCK_TS(block); } +static u32 idma32_prepare_ctllo(struct dw_dma_chan *dwc) +{ + struct dma_slave_config *sconfig = &dwc->dma_sconfig; + bool is_slave = is_slave_direction(dwc->direction); + u8 smsize = is_slave ? sconfig->src_maxburst : IDMA32_MSIZE_8; + u8 dmsize = is_slave ? sconfig->dst_maxburst : IDMA32_MSIZE_8; + + return DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN | + DWC_CTLL_DST_MSIZE(dmsize) | DWC_CTLL_SRC_MSIZE(smsize); +} + static void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst) { *maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0; @@ -126,6 +138,7 @@ int idma32_dma_probe(struct dw_dma_chip *chip) dw->initialize_chan = idma32_initialize_chan; dw->suspend_chan = idma32_suspend_chan; dw->resume_chan = idma32_resume_chan; + dw->prepare_ctllo = idma32_prepare_ctllo; dw->encode_maxburst = idma32_encode_maxburst; dw->bytes2block = idma32_bytes2block; dw->block2bytes = idma32_block2bytes; diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 6cf299facf45..07f91325e559 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -222,6 +222,16 @@ enum dw_dma_msize { /* iDMA 32-bit support */ +/* bursts size */ +enum idma32_msize { + IDMA32_MSIZE_1, + IDMA32_MSIZE_2, + IDMA32_MSIZE_4, + IDMA32_MSIZE_8, + IDMA32_MSIZE_16, + IDMA32_MSIZE_32, +}; + /* Bitfields in CTL_HI */ #define IDMA32C_CTLH_BLOCK_TS_MASK GENMASK(16, 0) #define IDMA32C_CTLH_BLOCK_TS(x) ((x) & IDMA32C_CTLH_BLOCK_TS_MASK) @@ -316,6 +326,7 @@ struct dw_dma { void (*initialize_chan)(struct dw_dma_chan *dwc); void (*suspend_chan)(struct dw_dma_chan *dwc, bool drain); void (*resume_chan)(struct dw_dma_chan *dwc, bool drain); + u32 (*prepare_ctllo)(struct dw_dma_chan *dwc); void (*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst); u32 (*bytes2block)(struct dw_dma_chan *dwc, size_t bytes, unsigned int width, size_t *len); -- cgit v1.2.3 From b466a37fbcc99ef79ea59e40ef6aa8391430b0d8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Jan 2019 13:07:41 +0200 Subject: dmaengine: dw: convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw/Kconfig | 2 ++ drivers/dma/dw/core.c | 5 +---- drivers/dma/dw/internal.h | 5 +---- drivers/dma/dw/pci.c | 5 +---- drivers/dma/dw/platform.c | 5 +---- drivers/dma/dw/regs.h | 5 +---- 6 files changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw/Kconfig b/drivers/dma/dw/Kconfig index 04b9728c1d26..e5162690de8f 100644 --- a/drivers/dma/dw/Kconfig +++ b/drivers/dma/dw/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + # # DMA engine configuration for dw # diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index b7e4dab28f8a..3a1ab52ffae0 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Core driver for the Synopsys DesignWare DMA Controller * * Copyright (C) 2007-2008 Atmel Corporation * Copyright (C) 2010-2011 ST Microelectronics * Copyright (C) 2013 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index fdcac21ea665..1dd7a4e6dd23 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver for the Synopsys DesignWare DMA Controller * * Copyright (C) 2013 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _DMA_DW_INTERNAL_H diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index e9ba25b4f950..e79a75db0852 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * PCI driver for the Synopsys DesignWare DMA Controller * * Copyright (C) 2013 Intel Corporation * Author: Andy Shevchenko - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index d5196c97e4f4..382dfd9e9600 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Platform driver for the Synopsys DesignWare DMA Controller * @@ -6,10 +7,6 @@ * Copyright (C) 2013 Intel Corporation * * Some parts of this driver are derived from the original dw_dmac. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 07f91325e559..3fce66ecee7a 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver for the Synopsys DesignWare AHB DMA Controller * * Copyright (C) 2005-2007 Atmel Corporation * Copyright (C) 2010-2011 ST Microelectronics * Copyright (C) 2016 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include -- cgit v1.2.3 From 5fde600537db4c61621783ae9d1c18f35e5e342c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 12:30:34 -0600 Subject: dmaengine: bcm2835: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Vinod Koul --- drivers/dma/bcm2835-dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 1a44c8086d77..7beec403c2c9 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -312,8 +312,7 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( return NULL; /* allocate and setup the descriptor. */ - d = kzalloc(sizeof(*d) + frames * sizeof(struct bcm2835_cb_entry), - gfp); + d = kzalloc(struct_size(d, cb_list, frames), gfp); if (!d) return NULL; -- cgit v1.2.3 From ed414d580310c3ec95abcef508035040e21a629d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 24 Dec 2018 00:52:17 -0600 Subject: dmaengine: dma-jz4780: Use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index a8b6225faa12..9ce0a386225b 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -838,9 +838,8 @@ static int jz4780_dma_probe(struct platform_device *pdev) if (!soc_data) return -EINVAL; - jzdma = devm_kzalloc(dev, sizeof(*jzdma) - + sizeof(*jzdma->chan) * soc_data->nb_channels, - GFP_KERNEL); + jzdma = devm_kzalloc(dev, struct_size(jzdma, chan, + soc_data->nb_channels), GFP_KERNEL); if (!jzdma) return -ENOMEM; -- cgit v1.2.3 From 55f53b9c1746bba0e1b3a8d82ff3abe7ad3b96ce Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 12:43:22 -0600 Subject: dmaengine: st_fdma: use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Acked-by: Patrice Chotard Signed-off-by: Vinod Koul --- drivers/dma/st_fdma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c index 954f7cf62bb1..bc7a1de3f29b 100644 --- a/drivers/dma/st_fdma.c +++ b/drivers/dma/st_fdma.c @@ -243,8 +243,7 @@ static struct st_fdma_desc *st_fdma_alloc_desc(struct st_fdma_chan *fchan, struct st_fdma_desc *fdesc; int i; - fdesc = kzalloc(sizeof(*fdesc) + - sizeof(struct st_fdma_sw_node) * sg_len, GFP_NOWAIT); + fdesc = kzalloc(struct_size(fdesc, node, sg_len), GFP_NOWAIT); if (!fdesc) return NULL; -- cgit v1.2.3 From edd3c389999678ddff93e72d04368ed576bf36f8 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 11:32:15 -0600 Subject: dmaengine: qcom: bam_dma: use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Vinod Koul --- drivers/dma/qcom/bam_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index 1617715aa6e0..cb860cb53c27 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -636,8 +636,8 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan, num_alloc += DIV_ROUND_UP(sg_dma_len(sg), BAM_FIFO_SIZE); /* allocate enough room to accomodate the number of entries */ - async_desc = kzalloc(sizeof(*async_desc) + - (num_alloc * sizeof(struct bam_desc_hw)), GFP_NOWAIT); + async_desc = kzalloc(struct_size(async_desc, desc, num_alloc), + GFP_NOWAIT); if (!async_desc) goto err_out; -- cgit v1.2.3 From d3d70373f6fee9ed41bc4e9f1acdbc80c5b3a684 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 15:16:12 -0600 Subject: dmaengine: tegra-apb: Use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 659b49bf6fdb..cf462b1abc0b 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -1329,8 +1329,9 @@ static int tegra_dma_probe(struct platform_device *pdev) return -ENODEV; } - tdma = devm_kzalloc(&pdev->dev, sizeof(*tdma) + cdata->nr_channels * - sizeof(struct tegra_dma_channel), GFP_KERNEL); + tdma = devm_kzalloc(&pdev->dev, + struct_size(tdma, channels, cdata->nr_channels), + GFP_KERNEL); if (!tdma) return -ENOMEM; -- cgit v1.2.3 From de1fa4f61be71725581c8e30f3665aaa20d1610e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 15:25:45 -0600 Subject: dmaengine: fsl-edma: use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Tested-by: Angelo Dureghello Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 8876c4c1bb2c..fe529100674f 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -339,9 +339,7 @@ static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan, struct fsl_edma_desc *fsl_desc; int i; - fsl_desc = kzalloc(sizeof(*fsl_desc) + - sizeof(struct fsl_edma_sw_tcd) * - sg_len, GFP_NOWAIT); + fsl_desc = kzalloc(struct_size(fsl_desc, tcd, sg_len), GFP_NOWAIT); if (!fsl_desc) return NULL; -- cgit v1.2.3 From 8d9981efbcab066d17af4d3c85c169200f6f78df Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:36 +0100 Subject: clk: meson: clean-up clock registration Order, ids and size between the table of regmap clocks and the onecell data table could be different. Set regmap pointer in all the regmap clocks before starting the registration using the onecell data, to make sure we don't get into an incoherent situation. Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-3-jbrunet@baylibre.com --- drivers/clk/meson/meson-aoclk.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index f965845917e3..258c8d259ea1 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -65,15 +65,20 @@ int meson_aoclkc_probe(struct platform_device *pdev) return ret; } - /* - * Populate regmap and register all clks - */ - for (clkid = 0; clkid < data->num_clks; clkid++) { + /* Populate regmap */ + for (clkid = 0; clkid < data->num_clks; clkid++) data->clks[clkid]->map = regmap; + /* Register all clks */ + for (clkid = 0; clkid < data->hw_data->num; clkid++) { + if (!data->hw_data->hws[clkid]) + continue; + ret = devm_clk_hw_register(dev, data->hw_data->hws[clkid]); - if (ret) + if (ret) { + dev_err(dev, "Clock registration failed\n"); return ret; + } } return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, -- cgit v1.2.3 From a8d552a63857c73c6f0ea28dc8a70df10764b820 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:37 +0100 Subject: clk: meson: add dual divider clock driver Add the dual divider driver. This special divider make a weighted average between 2 dividers to reach fractional divider values. Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-4-jbrunet@baylibre.com --- drivers/clk/meson/Makefile | 2 +- drivers/clk/meson/clk-dualdiv.c | 130 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/clkc.h | 19 ++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/meson/clk-dualdiv.c (limited to 'drivers') diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index a849aa809825..f1fcafc046d5 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o +obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o clk-dualdiv.o obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o diff --git a/drivers/clk/meson/clk-dualdiv.c b/drivers/clk/meson/clk-dualdiv.c new file mode 100644 index 000000000000..4d9e161de627 --- /dev/null +++ b/drivers/clk/meson/clk-dualdiv.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 BayLibre, SAS + * Author: Neil Armstrong + * Author: Jerome Brunet + */ + +/* + * The AO Domain embeds a dual/divider to generate a more precise + * 32,768KHz clock for low-power suspend mode and CEC. + * ______ ______ + * | | | | + * | Div1 |-| Cnt1 | + * /|______| |______|\ + * -| ______ ______ X--> Out + * \| | | |/ + * | Div2 |-| Cnt2 | + * |______| |______| + * + * The dividing can be switched to single or dual, with a counter + * for each divider to set when the switching is done. + */ + +#include +#include "clkc.h" + +static inline struct meson_clk_dualdiv_data * +meson_clk_dualdiv_data(struct clk_regmap *clk) +{ + return (struct meson_clk_dualdiv_data *)clk->data; +} + +static unsigned long +__dualdiv_param_to_rate(unsigned long parent_rate, + const struct meson_clk_dualdiv_param *p) +{ + if (!p->dual) + return DIV_ROUND_CLOSEST(parent_rate, p->n1); + + return DIV_ROUND_CLOSEST(parent_rate * (p->m1 + p->m2), + p->n1 * p->m1 + p->n2 * p->m2); +} + +static unsigned long meson_clk_dualdiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + struct meson_clk_dualdiv_param setting; + + setting.dual = meson_parm_read(clk->map, &dualdiv->dual); + setting.n1 = meson_parm_read(clk->map, &dualdiv->n1) + 1; + setting.m1 = meson_parm_read(clk->map, &dualdiv->m1) + 1; + setting.n2 = meson_parm_read(clk->map, &dualdiv->n2) + 1; + setting.m2 = meson_parm_read(clk->map, &dualdiv->m2) + 1; + + return __dualdiv_param_to_rate(parent_rate, &setting); +} + +static const struct meson_clk_dualdiv_param * +__dualdiv_get_setting(unsigned long rate, unsigned long parent_rate, + struct meson_clk_dualdiv_data *dualdiv) +{ + const struct meson_clk_dualdiv_param *table = dualdiv->table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; + + if (!table) + return NULL; + + for (i = 0; table[i].n1; i++) { + now = __dualdiv_param_to_rate(parent_rate, &table[i]); + + /* If we get an exact match, don't bother any further */ + if (now == rate) { + return &table[i]; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + return (struct meson_clk_dualdiv_param *)&table[best_i]; +} + +static long meson_clk_dualdiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + const struct meson_clk_dualdiv_param *setting = + __dualdiv_get_setting(rate, *parent_rate, dualdiv); + + if (!setting) + return meson_clk_dualdiv_recalc_rate(hw, *parent_rate); + + return __dualdiv_param_to_rate(*parent_rate, setting); +} + +static int meson_clk_dualdiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + const struct meson_clk_dualdiv_param *setting = + __dualdiv_get_setting(rate, parent_rate, dualdiv); + + if (!setting) + return -EINVAL; + + meson_parm_write(clk->map, &dualdiv->dual, setting->dual); + meson_parm_write(clk->map, &dualdiv->n1, setting->n1 - 1); + meson_parm_write(clk->map, &dualdiv->m1, setting->m1 - 1); + meson_parm_write(clk->map, &dualdiv->n2, setting->n2 - 1); + meson_parm_write(clk->map, &dualdiv->m2, setting->m2 - 1); + + return 0; +} + +const struct clk_ops meson_clk_dualdiv_ops = { + .recalc_rate = meson_clk_dualdiv_recalc_rate, + .round_rate = meson_clk_dualdiv_round_rate, + .set_rate = meson_clk_dualdiv_set_rate, +}; +EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ops); + +const struct clk_ops meson_clk_dualdiv_ro_ops = { + .recalc_rate = meson_clk_dualdiv_recalc_rate, +}; +EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ro_ops); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 6183b22c4bf2..e3cd442db739 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -110,6 +110,23 @@ struct clk_regmap _name = { \ }, \ }; +struct meson_clk_dualdiv_param { + unsigned int n1; + unsigned int n2; + unsigned int m1; + unsigned int m2; + unsigned int dual; +}; + +struct meson_clk_dualdiv_data { + struct parm n1; + struct parm n2; + struct parm m1; + struct parm m2; + struct parm dual; + const struct meson_clk_dualdiv_param *table; +}; + /* clk_ops */ extern const struct clk_ops meson_clk_pll_ro_ops; extern const struct clk_ops meson_clk_pll_ops; @@ -118,6 +135,8 @@ extern const struct clk_ops meson_clk_mpll_ro_ops; extern const struct clk_ops meson_clk_mpll_ops; extern const struct clk_ops meson_clk_phase_ops; extern const struct clk_ops meson_vid_pll_div_ro_ops; +extern const struct clk_ops meson_clk_dualdiv_ops; +extern const struct clk_ops meson_clk_dualdiv_ro_ops; struct clk_hw *meson_clk_hw_register_input(struct device *dev, const char *of_name, -- cgit v1.2.3 From b249623fd1472225232e8784864af55aec1fd81b Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:38 +0100 Subject: clk: meson: gxbb-ao: replace cec-32k with the dual divider Replace the cec-32k clock of gxbb-ao with the simpler dual divider driver. The dual divider implements only the dividing part. All the other bits are now exposed using simple elements, such as gates and muxes Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-5-jbrunet@baylibre.com --- drivers/clk/meson/Makefile | 2 +- drivers/clk/meson/gxbb-aoclk-32k.c | 193 ---------------------------- drivers/clk/meson/gxbb-aoclk.c | 251 +++++++++++++++++++++++++++++-------- drivers/clk/meson/gxbb-aoclk.h | 20 +-- 4 files changed, 204 insertions(+), 262 deletions(-) delete mode 100644 drivers/clk/meson/gxbb-aoclk-32k.c (limited to 'drivers') diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index f1fcafc046d5..8234e92eea38 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o clk-dualdiv.o obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o -obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o diff --git a/drivers/clk/meson/gxbb-aoclk-32k.c b/drivers/clk/meson/gxbb-aoclk-32k.c deleted file mode 100644 index 680467141a1d..000000000000 --- a/drivers/clk/meson/gxbb-aoclk-32k.c +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2017 BayLibre, SAS. - * Author: Neil Armstrong - */ - -#include -#include -#include -#include "gxbb-aoclk.h" - -/* - * The AO Domain embeds a dual/divider to generate a more precise - * 32,768KHz clock for low-power suspend mode and CEC. - * ______ ______ - * | | | | - * ______ | Div1 |-| Cnt1 | ______ - * | | /|______| |______|\ | | - * Xtal-->| Gate |---| ______ ______ X-X--| Gate |--> - * |______| | \| | | |/ | |______| - * | | Div2 |-| Cnt2 | | - * | |______| |______| | - * |_______________________| - * - * The dividing can be switched to single or dual, with a counter - * for each divider to set when the switching is done. - * The entire dividing mechanism can be also bypassed. - */ - -#define CLK_CNTL0_N1_MASK GENMASK(11, 0) -#define CLK_CNTL0_N2_MASK GENMASK(23, 12) -#define CLK_CNTL0_DUALDIV_EN BIT(28) -#define CLK_CNTL0_OUT_GATE_EN BIT(30) -#define CLK_CNTL0_IN_GATE_EN BIT(31) - -#define CLK_CNTL1_M1_MASK GENMASK(11, 0) -#define CLK_CNTL1_M2_MASK GENMASK(23, 12) -#define CLK_CNTL1_BYPASS_EN BIT(24) -#define CLK_CNTL1_SELECT_OSC BIT(27) - -#define PWR_CNTL_ALT_32K_SEL GENMASK(13, 10) - -struct cec_32k_freq_table { - unsigned long parent_rate; - unsigned long target_rate; - bool dualdiv; - unsigned int n1; - unsigned int n2; - unsigned int m1; - unsigned int m2; -}; - -static const struct cec_32k_freq_table aoclk_cec_32k_table[] = { - [0] = { - .parent_rate = 24000000, - .target_rate = 32768, - .dualdiv = true, - .n1 = 733, - .n2 = 732, - .m1 = 8, - .m2 = 11, - }, -}; - -/* - * If CLK_CNTL0_DUALDIV_EN == 0 - * - will use N1 divider only - * If CLK_CNTL0_DUALDIV_EN == 1 - * - hold M1 cycles of N1 divider then changes to N2 - * - hold M2 cycles of N2 divider then changes to N1 - * Then we can get more accurate division. - */ -static unsigned long aoclk_cec_32k_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw); - unsigned long n1; - u32 reg0, reg1; - - regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, ®0); - regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, ®1); - - if (reg1 & CLK_CNTL1_BYPASS_EN) - return parent_rate; - - if (reg0 & CLK_CNTL0_DUALDIV_EN) { - unsigned long n2, m1, m2, f1, f2, p1, p2; - - n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1; - n2 = FIELD_GET(CLK_CNTL0_N2_MASK, reg0) + 1; - - m1 = FIELD_GET(CLK_CNTL1_M1_MASK, reg1) + 1; - m2 = FIELD_GET(CLK_CNTL1_M2_MASK, reg1) + 1; - - f1 = DIV_ROUND_CLOSEST(parent_rate, n1); - f2 = DIV_ROUND_CLOSEST(parent_rate, n2); - - p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2)); - p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2)); - - return DIV_ROUND_UP(100000000, p1 + p2); - } - - n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1; - - return DIV_ROUND_CLOSEST(parent_rate, n1); -} - -static const struct cec_32k_freq_table *find_cec_32k_freq(unsigned long rate, - unsigned long prate) -{ - int i; - - for (i = 0 ; i < ARRAY_SIZE(aoclk_cec_32k_table) ; ++i) - if (aoclk_cec_32k_table[i].parent_rate == prate && - aoclk_cec_32k_table[i].target_rate == rate) - return &aoclk_cec_32k_table[i]; - - return NULL; -} - -static long aoclk_cec_32k_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate, - *prate); - - /* If invalid return first one */ - if (!freq) - return aoclk_cec_32k_table[0].target_rate; - - return freq->target_rate; -} - -/* - * From the Amlogic init procedure, the IN and OUT gates needs to be handled - * in the init procedure to avoid any glitches. - */ - -static int aoclk_cec_32k_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate, - parent_rate); - struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw); - u32 reg = 0; - - if (!freq) - return -EINVAL; - - /* Disable clock */ - regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, - CLK_CNTL0_IN_GATE_EN | CLK_CNTL0_OUT_GATE_EN, 0); - - reg = FIELD_PREP(CLK_CNTL0_N1_MASK, freq->n1 - 1); - if (freq->dualdiv) - reg |= CLK_CNTL0_DUALDIV_EN | - FIELD_PREP(CLK_CNTL0_N2_MASK, freq->n2 - 1); - - regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, reg); - - reg = FIELD_PREP(CLK_CNTL1_M1_MASK, freq->m1 - 1); - if (freq->dualdiv) - reg |= FIELD_PREP(CLK_CNTL1_M2_MASK, freq->m2 - 1); - - regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, reg); - - /* Enable clock */ - regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, - CLK_CNTL0_IN_GATE_EN, CLK_CNTL0_IN_GATE_EN); - - udelay(200); - - regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, - CLK_CNTL0_OUT_GATE_EN, CLK_CNTL0_OUT_GATE_EN); - - regmap_update_bits(cec_32k->regmap, AO_CRT_CLK_CNTL1, - CLK_CNTL1_SELECT_OSC, CLK_CNTL1_SELECT_OSC); - - /* Select 32k from XTAL */ - regmap_update_bits(cec_32k->regmap, - AO_RTI_PWR_CNTL_REG0, - PWR_CNTL_ALT_32K_SEL, - FIELD_PREP(PWR_CNTL_ALT_32K_SEL, 4)); - - return 0; -} - -const struct clk_ops meson_aoclk_cec_32k_ops = { - .recalc_rate = aoclk_cec_32k_recalc_rate, - .round_rate = aoclk_cec_32k_round_rate, - .set_rate = aoclk_cec_32k_set_rate, -}; diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 42ed61d3c3fb..5fa57b623b8f 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -5,10 +5,19 @@ */ #include #include -#include "clk-regmap.h" +#include "clkc.h" #include "meson-aoclk.h" #include "gxbb-aoclk.h" +/* AO Configuration Clock registers offsets */ +#define AO_RTI_PWR_CNTL_REG1 0x0c +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_OSCIN_CNTL 0x58 +#define AO_CRT_CLK_CNTL1 0x68 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + #define GXBB_AO_GATE(_name, _bit) \ static struct clk_regmap _name##_ao = { \ .data = &(struct clk_regmap_gate_data) { \ @@ -31,13 +40,174 @@ GXBB_AO_GATE(uart1, 3); GXBB_AO_GATE(uart2, 5); GXBB_AO_GATE(ir_blaster, 6); -static struct aoclk_cec_32k cec_32k_ao = { - .hw.init = &(struct clk_init_data) { - .name = "cec_32k_ao", - .ops = &meson_aoclk_cec_32k_ops, +static struct clk_regmap ao_cts_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTI_PWR_CNTL_REG0, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_oscin", + .ops = &clk_regmap_gate_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap ao_32k_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_pre", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "ao_cts_oscin" }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param gxbb_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, {} +}; + +static struct clk_regmap ao_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 28, + .width = 1, + }, + .table = gxbb_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_names = (const char *[]){ "ao_32k_pre" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap ao_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_ALT_CLK_CNTL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "ao_32k_div", + "ao_32k_pre" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap ao_32k = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "ao_32k_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap ao_cts_rtc_oscin = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x7, + .shift = 10, + .table = (u32[]){ 1, 2, 3, 4 }, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "ext_32k_0", + "ext_32k_1", + "ext_32k_2", + "ao_32k" }, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap ao_clk81 = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 0, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_clk81", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "clk81", + "ao_cts_rtc_oscin" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap ao_cts_cec = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_CRT_CLK_CNTL1, + .mask = 0x1, + .shift = 27, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_cec", + .ops = &clk_regmap_mux_ops, + /* + * FIXME: The 'fixme' parent obviously does not exist. + * + * ATM, CCF won't call get_parent() if num_parents is 1. It + * does not allow NULL as a parent name either. + * + * On this particular mux, we only know the input #1 parent + * but, on boot, unknown input #0 is set, so it is critical + * to call .get_parent() on it + * + * Until CCF gets fixed, adding this fake parent that won't + * ever be registered should work around the problem + */ + .parent_names = (const char *[]){ "fixme", + "ao_cts_rtc_oscin" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -50,13 +220,21 @@ static const unsigned int gxbb_aoclk_reset[] = { [RESET_AO_IR_BLASTER] = 23, }; -static struct clk_regmap *gxbb_aoclk_gate[] = { - [CLKID_AO_REMOTE] = &remote_ao, - [CLKID_AO_I2C_MASTER] = &i2c_master_ao, - [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, - [CLKID_AO_UART1] = &uart1_ao, - [CLKID_AO_UART2] = &uart2_ao, - [CLKID_AO_IR_BLASTER] = &ir_blaster_ao, +static struct clk_regmap *gxbb_aoclk[] = { + &remote_ao, + &i2c_master_ao, + &i2c_slave_ao, + &uart1_ao, + &uart2_ao, + &ir_blaster_ao, + &ao_cts_oscin, + &ao_32k_pre, + &ao_32k_div, + &ao_32k_sel, + &ao_32k, + &ao_cts_rtc_oscin, + &ao_clk81, + &ao_cts_cec, }; static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { @@ -67,52 +245,27 @@ static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { [CLKID_AO_UART1] = &uart1_ao.hw, [CLKID_AO_UART2] = &uart2_ao.hw, [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, - [CLKID_AO_CEC_32K] = &cec_32k_ao.hw, + [CLKID_AO_CEC_32K] = &ao_cts_cec.hw, + [CLKID_AO_CTS_OSCIN] = &ao_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &ao_32k_pre.hw, + [CLKID_AO_32K_DIV] = &ao_32k_div.hw, + [CLKID_AO_32K_SEL] = &ao_32k_sel.hw, + [CLKID_AO_32K] = &ao_32k.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &ao_cts_rtc_oscin.hw, + [CLKID_AO_CLK81] = &ao_clk81.hw, }, .num = NR_CLKS, }; -static int gxbb_register_cec_ao_32k(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct regmap *regmap; - int ret; - - regmap = syscon_node_to_regmap(of_get_parent(dev->of_node)); - if (IS_ERR(regmap)) { - dev_err(dev, "failed to get regmap\n"); - return PTR_ERR(regmap); - } - - /* Specific clocks */ - cec_32k_ao.regmap = regmap; - ret = devm_clk_hw_register(dev, &cec_32k_ao.hw); - if (ret) { - dev_err(&pdev->dev, "clk cec_32k_ao register failed.\n"); - return ret; - } - - return 0; -} - static const struct meson_aoclk_data gxbb_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(gxbb_aoclk_reset), .reset = gxbb_aoclk_reset, - .num_clks = ARRAY_SIZE(gxbb_aoclk_gate), - .clks = gxbb_aoclk_gate, + .num_clks = ARRAY_SIZE(gxbb_aoclk), + .clks = gxbb_aoclk, .hw_data = &gxbb_aoclk_onecell_data, }; -static int gxbb_aoclkc_probe(struct platform_device *pdev) -{ - int ret = gxbb_register_cec_ao_32k(pdev); - if (ret) - return ret; - - return meson_aoclkc_probe(pdev); -} - static const struct of_device_id gxbb_aoclkc_match_table[] = { { .compatible = "amlogic,meson-gx-aoclkc", @@ -122,7 +275,7 @@ static const struct of_device_id gxbb_aoclkc_match_table[] = { }; static struct platform_driver gxbb_aoclkc_driver = { - .probe = gxbb_aoclkc_probe, + .probe = meson_aoclkc_probe, .driver = { .name = "gxbb-aoclkc", .of_match_table = gxbb_aoclkc_match_table, diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h index c514493d989a..1db16f9b37d4 100644 --- a/drivers/clk/meson/gxbb-aoclk.h +++ b/drivers/clk/meson/gxbb-aoclk.h @@ -7,25 +7,7 @@ #ifndef __GXBB_AOCLKC_H #define __GXBB_AOCLKC_H -#define NR_CLKS 7 - -/* AO Configuration Clock registers offsets */ -#define AO_RTI_PWR_CNTL_REG1 0x0c -#define AO_RTI_PWR_CNTL_REG0 0x10 -#define AO_RTI_GEN_CNTL_REG0 0x40 -#define AO_OSCIN_CNTL 0x58 -#define AO_CRT_CLK_CNTL1 0x68 -#define AO_RTC_ALT_CLK_CNTL0 0x94 -#define AO_RTC_ALT_CLK_CNTL1 0x98 - -struct aoclk_cec_32k { - struct clk_hw hw; - struct regmap *regmap; -}; - -#define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw) - -extern const struct clk_ops meson_aoclk_cec_32k_ops; +#define NR_CLKS 14 #include #include -- cgit v1.2.3 From 172e95346d5e3b364d71e3980c966cf323e0fdd7 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:39 +0100 Subject: clk: meson: axg-ao: add 32k generation subtree Add the clock subtree generating the 32k clock in amlogic axg ao block. Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-6-jbrunet@baylibre.com --- drivers/clk/meson/axg-aoclk.c | 175 ++++++++++++++++++++++++++++++++++++++---- drivers/clk/meson/axg-aoclk.h | 13 +--- 2 files changed, 163 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index 29e088542387..5f518be144ce 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -12,10 +12,23 @@ #include #include #include -#include "clk-regmap.h" +#include "clkc.h" #include "meson-aoclk.h" #include "axg-aoclk.h" +/* + * AO Configuration Clock registers offsets + * Register offsets from the data sheet must be multiplied by 4. + */ +#define AO_RTI_PWR_CNTL_REG1 0x0C +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_OSCIN_CNTL 0x58 +#define AO_CRT_CLK_CNTL1 0x68 +#define AO_SAR_CLK 0x90 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + #define AXG_AO_GATE(_name, _bit) \ static struct clk_regmap axg_aoclk_##_name = { \ .data = &(struct clk_regmap_gate_data) { \ @@ -39,17 +52,141 @@ AXG_AO_GATE(uart2, 5); AXG_AO_GATE(ir_blaster, 6); AXG_AO_GATE(saradc, 7); +static struct clk_regmap axg_aoclk_cts_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTI_PWR_CNTL_REG0, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_oscin", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_aoclk_32k_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_pre", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "cts_oscin" }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param axg_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, {} +}; + +static struct clk_regmap axg_aoclk_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 28, + .width = 1, + }, + .table = axg_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_names = (const char *[]){ "axg_ao_32k_pre" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_aoclk_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_ALT_CLK_CNTL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "axg_ao_32k_div", + "axg_ao_32k_pre" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_aoclk_32k = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "axg_ao_32k_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_aoclk_cts_rtc_oscin = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 10, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "axg_ao_32k", + "axg_ext_32k" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap axg_aoclk_clk81 = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTI_PWR_CNTL_REG0, .mask = 0x1, .shift = 8, + .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ .name = "axg_ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "clk81", "ao_alt_xtal"}, + .parent_names = (const char *[]){ "clk81", + "axg_ao_cts_rtc_oscin"}, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -106,17 +243,23 @@ static const unsigned int axg_aoclk_reset[] = { }; static struct clk_regmap *axg_aoclk_regmap[] = { - [CLKID_AO_REMOTE] = &axg_aoclk_remote, - [CLKID_AO_I2C_MASTER] = &axg_aoclk_i2c_master, - [CLKID_AO_I2C_SLAVE] = &axg_aoclk_i2c_slave, - [CLKID_AO_UART1] = &axg_aoclk_uart1, - [CLKID_AO_UART2] = &axg_aoclk_uart2, - [CLKID_AO_IR_BLASTER] = &axg_aoclk_ir_blaster, - [CLKID_AO_SAR_ADC] = &axg_aoclk_saradc, - [CLKID_AO_CLK81] = &axg_aoclk_clk81, - [CLKID_AO_SAR_ADC_SEL] = &axg_aoclk_saradc_mux, - [CLKID_AO_SAR_ADC_DIV] = &axg_aoclk_saradc_div, - [CLKID_AO_SAR_ADC_CLK] = &axg_aoclk_saradc_gate, + &axg_aoclk_remote, + &axg_aoclk_i2c_master, + &axg_aoclk_i2c_slave, + &axg_aoclk_uart1, + &axg_aoclk_uart2, + &axg_aoclk_ir_blaster, + &axg_aoclk_saradc, + &axg_aoclk_cts_oscin, + &axg_aoclk_32k_pre, + &axg_aoclk_32k_div, + &axg_aoclk_32k_sel, + &axg_aoclk_32k, + &axg_aoclk_cts_rtc_oscin, + &axg_aoclk_clk81, + &axg_aoclk_saradc_mux, + &axg_aoclk_saradc_div, + &axg_aoclk_saradc_gate, }; static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { @@ -132,6 +275,12 @@ static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { [CLKID_AO_SAR_ADC_SEL] = &axg_aoclk_saradc_mux.hw, [CLKID_AO_SAR_ADC_DIV] = &axg_aoclk_saradc_div.hw, [CLKID_AO_SAR_ADC_CLK] = &axg_aoclk_saradc_gate.hw, + [CLKID_AO_CTS_OSCIN] = &axg_aoclk_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &axg_aoclk_32k_pre.hw, + [CLKID_AO_32K_DIV] = &axg_aoclk_32k_div.hw, + [CLKID_AO_32K_SEL] = &axg_aoclk_32k_sel.hw, + [CLKID_AO_32K] = &axg_aoclk_32k.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &axg_aoclk_cts_rtc_oscin.hw, }, .num = NR_CLKS, }; diff --git a/drivers/clk/meson/axg-aoclk.h b/drivers/clk/meson/axg-aoclk.h index 91384d8dd844..3cc27e85170f 100644 --- a/drivers/clk/meson/axg-aoclk.h +++ b/drivers/clk/meson/axg-aoclk.h @@ -10,18 +10,7 @@ #ifndef __AXG_AOCLKC_H #define __AXG_AOCLKC_H -#define NR_CLKS 11 -/* AO Configuration Clock registers offsets - * Register offsets from the data sheet must be multiplied by 4. - */ -#define AO_RTI_PWR_CNTL_REG1 0x0C -#define AO_RTI_PWR_CNTL_REG0 0x10 -#define AO_RTI_GEN_CNTL_REG0 0x40 -#define AO_OSCIN_CNTL 0x58 -#define AO_CRT_CLK_CNTL1 0x68 -#define AO_SAR_CLK 0x90 -#define AO_RTC_ALT_CLK_CNTL0 0x94 -#define AO_RTC_ALT_CLK_CNTL1 0x98 +#define NR_CLKS 17 #include #include -- cgit v1.2.3 From cce433e6bc53b3984274c61c78d0dadb87483646 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 8 Dec 2018 18:12:44 +0100 Subject: clk: meson: meson8b: use a separate clock table for Meson8 The Meson8 SoC is slightly different compared to Meson8b and Meson8m2 because it does not have the glitch-free Mali GPU clock mux. For Meson8b and Meson8m2 there are currently no known differences. Add a separate clk_hw_onecell_data table for Meson8 so these differences can be implemented. For now meson8_hw_onecell_data is a clone of our existing meson8b_hw_onecell_data. Signed-off-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181208171247.22238-3-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 203 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 197 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 950d0e548c75..0b9353d8d4fd 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1659,6 +1659,185 @@ static MESON_GATE(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1); static MESON_GATE(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2); static MESON_GATE(meson8b_ao_iface, HHI_GCLK_AO, 3); +static struct clk_hw_onecell_data meson8_hw_onecell_data = { + .hws = { + [CLKID_XTAL] = &meson8b_xtal.hw, + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_DDR] = &meson8b_ddr.hw, + [CLKID_DOS] = &meson8b_dos.hw, + [CLKID_ISA] = &meson8b_isa.hw, + [CLKID_PL301] = &meson8b_pl301.hw, + [CLKID_PERIPHS] = &meson8b_periphs.hw, + [CLKID_SPICC] = &meson8b_spicc.hw, + [CLKID_I2C] = &meson8b_i2c.hw, + [CLKID_SAR_ADC] = &meson8b_sar_adc.hw, + [CLKID_SMART_CARD] = &meson8b_smart_card.hw, + [CLKID_RNG0] = &meson8b_rng0.hw, + [CLKID_UART0] = &meson8b_uart0.hw, + [CLKID_SDHC] = &meson8b_sdhc.hw, + [CLKID_STREAM] = &meson8b_stream.hw, + [CLKID_ASYNC_FIFO] = &meson8b_async_fifo.hw, + [CLKID_SDIO] = &meson8b_sdio.hw, + [CLKID_ABUF] = &meson8b_abuf.hw, + [CLKID_HIU_IFACE] = &meson8b_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &meson8b_assist_misc.hw, + [CLKID_SPI] = &meson8b_spi.hw, + [CLKID_I2S_SPDIF] = &meson8b_i2s_spdif.hw, + [CLKID_ETH] = &meson8b_eth.hw, + [CLKID_DEMUX] = &meson8b_demux.hw, + [CLKID_AIU_GLUE] = &meson8b_aiu_glue.hw, + [CLKID_IEC958] = &meson8b_iec958.hw, + [CLKID_I2S_OUT] = &meson8b_i2s_out.hw, + [CLKID_AMCLK] = &meson8b_amclk.hw, + [CLKID_AIFIFO2] = &meson8b_aififo2.hw, + [CLKID_MIXER] = &meson8b_mixer.hw, + [CLKID_MIXER_IFACE] = &meson8b_mixer_iface.hw, + [CLKID_ADC] = &meson8b_adc.hw, + [CLKID_BLKMV] = &meson8b_blkmv.hw, + [CLKID_AIU] = &meson8b_aiu.hw, + [CLKID_UART1] = &meson8b_uart1.hw, + [CLKID_G2D] = &meson8b_g2d.hw, + [CLKID_USB0] = &meson8b_usb0.hw, + [CLKID_USB1] = &meson8b_usb1.hw, + [CLKID_RESET] = &meson8b_reset.hw, + [CLKID_NAND] = &meson8b_nand.hw, + [CLKID_DOS_PARSER] = &meson8b_dos_parser.hw, + [CLKID_USB] = &meson8b_usb.hw, + [CLKID_VDIN1] = &meson8b_vdin1.hw, + [CLKID_AHB_ARB0] = &meson8b_ahb_arb0.hw, + [CLKID_EFUSE] = &meson8b_efuse.hw, + [CLKID_BOOT_ROM] = &meson8b_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &meson8b_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &meson8b_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &meson8b_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &meson8b_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &meson8b_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &meson8b_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &meson8b_mmc_pclk.hw, + [CLKID_DVIN] = &meson8b_dvin.hw, + [CLKID_UART2] = &meson8b_uart2.hw, + [CLKID_SANA] = &meson8b_sana.hw, + [CLKID_VPU_INTR] = &meson8b_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A9] = &meson8b_clk81_a9.hw, + [CLKID_VCLK2_VENCI0] = &meson8b_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &meson8b_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, + [CLKID_GCLK_VENCP_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, + [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, + [CLKID_ENC480P] = &meson8b_enc480p.hw, + [CLKID_RNG1] = &meson8b_rng1.hw, + [CLKID_GCLK_VENCL_INT] = &meson8b_gclk_vencl_int.hw, + [CLKID_VCLK2_VENCLMCC] = &meson8b_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &meson8b_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER] = &meson8b_vclk2_other.hw, + [CLKID_EDP] = &meson8b_edp.hw, + [CLKID_AO_MEDIA_CPU] = &meson8b_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, + [CLKID_MPLL0] = &meson8b_mpll0.hw, + [CLKID_MPLL1] = &meson8b_mpll1.hw, + [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, + [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, + [CLKID_CPU_IN_DIV2] = &meson8b_cpu_in_div2.hw, + [CLKID_CPU_IN_DIV3] = &meson8b_cpu_in_div3.hw, + [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, + [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, + [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, + [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, + [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, + [CLKID_CPU_CLK_DIV2] = &meson8b_cpu_clk_div2.hw, + [CLKID_CPU_CLK_DIV3] = &meson8b_cpu_clk_div3.hw, + [CLKID_CPU_CLK_DIV4] = &meson8b_cpu_clk_div4.hw, + [CLKID_CPU_CLK_DIV5] = &meson8b_cpu_clk_div5.hw, + [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, + [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, + [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, + [CLKID_ABP_SEL] = &meson8b_abp_clk_sel.hw, + [CLKID_ABP] = &meson8b_abp_clk_gate.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_clk_sel.hw, + [CLKID_PERIPH] = &meson8b_periph_clk_gate.hw, + [CLKID_AXI_SEL] = &meson8b_axi_clk_sel.hw, + [CLKID_AXI] = &meson8b_axi_clk_gate.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_clk_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram_clk_gate.hw, + [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, + [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, + [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, + [CLKID_VID_PLL_IN_EN] = &meson8b_vid_pll_in_en.hw, + [CLKID_VID_PLL_PRE_DIV] = &meson8b_vid_pll_pre_div.hw, + [CLKID_VID_PLL_POST_DIV] = &meson8b_vid_pll_post_div.hw, + [CLKID_VID_PLL_FINAL_DIV] = &meson8b_vid_pll_final_div.hw, + [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, + [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1_gate.hw, + [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2_div_gate.hw, + [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4_div_gate.hw, + [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6_div_gate.hw, + [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12_div_gate.hw, + [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_clk_in_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1_gate.hw, + [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2_div_gate.hw, + [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4_div_gate.hw, + [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6_div_gate.hw, + [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12_div_gate.hw, + [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, + [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, + [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, + [CLKID_CTS_ENCP] = &meson8b_cts_encp.hw, + [CLKID_CTS_ENCI_SEL] = &meson8b_cts_enci_sel.hw, + [CLKID_CTS_ENCI] = &meson8b_cts_enci.hw, + [CLKID_HDMI_TX_PIXEL_SEL] = &meson8b_hdmi_tx_pixel_sel.hw, + [CLKID_HDMI_TX_PIXEL] = &meson8b_hdmi_tx_pixel.hw, + [CLKID_CTS_ENCL_SEL] = &meson8b_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &meson8b_cts_encl.hw, + [CLKID_CTS_VDAC0_SEL] = &meson8b_cts_vdac0_sel.hw, + [CLKID_CTS_VDAC0] = &meson8b_cts_vdac0.hw, + [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, + [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, + [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLK_NR_CLKS] = NULL, + }, + .num = CLK_NR_CLKS, +}; + static struct clk_hw_onecell_data meson8b_hw_onecell_data = { .hws = { [CLKID_XTAL] = &meson8b_xtal.hw, @@ -2132,7 +2311,6 @@ static int meson8b_cpu_clk_notifier_cb(struct notifier_block *nb, static struct meson8b_nb_data meson8b_cpu_nb_data = { .nb.notifier_call = meson8b_cpu_clk_notifier_cb, - .onecell_data = &meson8b_hw_onecell_data, }; static const struct regmap_config clkc_regmap_config = { @@ -2141,7 +2319,8 @@ static const struct regmap_config clkc_regmap_config = { .reg_stride = 4, }; -static void __init meson8b_clkc_init(struct device_node *np) +static void __init meson8b_clkc_init_common(struct device_node *np, + struct clk_hw_onecell_data *clk_hw_onecell_data) { struct meson8b_clk_reset *rstc; const char *notifier_clk_name; @@ -2192,14 +2371,16 @@ static void __init meson8b_clkc_init(struct device_node *np) */ for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { /* array might be sparse */ - if (!meson8b_hw_onecell_data.hws[i]) + if (!clk_hw_onecell_data->hws[i]) continue; - ret = clk_hw_register(NULL, meson8b_hw_onecell_data.hws[i]); + ret = clk_hw_register(NULL, clk_hw_onecell_data->hws[i]); if (ret) return; } + meson8b_cpu_nb_data.onecell_data = clk_hw_onecell_data; + /* * FIXME we shouldn't program the muxes in notifier handlers. The * tricky programming sequence will be handled by the forthcoming @@ -2215,13 +2396,23 @@ static void __init meson8b_clkc_init(struct device_node *np) } ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, - &meson8b_hw_onecell_data); + clk_hw_onecell_data); if (ret) pr_err("%s: failed to register clock provider\n", __func__); } +static void __init meson8_clkc_init(struct device_node *np) +{ + return meson8b_clkc_init_common(np, &meson8_hw_onecell_data); +} + +static void __init meson8b_clkc_init(struct device_node *np) +{ + return meson8b_clkc_init_common(np, &meson8b_hw_onecell_data); +} + CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc", - meson8b_clkc_init); + meson8_clkc_init); CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc", meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc", -- cgit v1.2.3 From 74e1f2521f16ffe38f1e49681a96588082f4406b Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 8 Dec 2018 18:12:45 +0100 Subject: clk: meson: meson8b: add the GPU clock tree Add the GPU clock tree on Meson8, Meson8b and Meson8m2. The GPU clock tree on Meson8b and Meson8m2 is almost identical to the one one GXBB: - there's a glitch-free mux at HHI_MALI_CLK_CNTL[31] - there are two identical parents for this mux: mali_0 and mali_1, each with a gate, divider and mux - the parents of mali_0_sel and mali_1_sel are identical to GXBB except there's no GP0_PLL on these 32-bit SoCs Meson8 is different because it does not have the glitch-free mux. Instead if only has the mali_0 clock tree. The parents of mali_0_sel are identical to the ones on Meson8b and Meson8m2. Signed-off-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181208171247.22238-4-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/meson8b.h | 9 ++- 2 files changed, 154 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 0b9353d8d4fd..748552c5f6c8 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1573,6 +1573,135 @@ static struct clk_regmap meson8b_hdmi_sys = { }, }; +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch on Meson8b and Meson8m2. Meson8 only + * has mali_0 and no glitch-free mux. + */ +static const char * const meson8b_mali_0_1_parent_names[] = { + "xtal", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", + "fclk_div5" +}; + +static u32 meson8b_mali_0_1_mux_table[] = { 0, 2, 3, 4, 5, 6, 7 }; + +static struct clk_regmap meson8b_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .table = meson8b_mali_0_1_mux_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = meson8b_mali_0_1_parent_names, + .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names), + /* + * Don't propagate rate changes up because the only changeable + * parents are mpll1 and mpll2 but we need those for audio and + * RGMII (Ethernet). We don't want to change the audio or + * Ethernet clocks when setting the GPU frequency. + */ + .flags = 0, + }, +}; + +static struct clk_regmap meson8b_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "mali_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mali_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .table = meson8b_mali_0_1_mux_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = meson8b_mali_0_1_parent_names, + .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names), + /* + * Don't propagate rate changes up because the only changeable + * parents are mpll1 and mpll2 but we need those for audio and + * RGMII (Ethernet). We don't want to change the audio or + * Ethernet clocks when setting the GPU frequency. + */ + .flags = 0, + }, +}; + +static struct clk_regmap meson8b_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "mali_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mali_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "mali_0", "mali_1" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); @@ -1833,6 +1962,9 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = { [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, + [CLKID_MALI] = &meson8b_mali_0.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -2012,6 +2144,13 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, + [CLKID_MALI_0] = &meson8b_mali_0.hw, + [CLKID_MALI_1_SEL] = &meson8b_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &meson8b_mali_1_div.hw, + [CLKID_MALI_1] = &meson8b_mali_1.hw, + [CLKID_MALI] = &meson8b_mali.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -2167,6 +2306,13 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_hdmi_sys_sel, &meson8b_hdmi_sys_div, &meson8b_hdmi_sys, + &meson8b_mali_0_sel, + &meson8b_mali_0_div, + &meson8b_mali_0, + &meson8b_mali_1_sel, + &meson8b_mali_1_div, + &meson8b_mali_1, + &meson8b_mali, }; static const struct meson8b_clk_reset_line { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 87fba739af81..f212e2304ff5 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -33,6 +33,7 @@ #define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ #define HHI_VID_DIVIDER_CNTL 0x198 /* 0x66 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */ +#define HHI_MALI_CLK_CNTL 0x1b0 /* 0x6c offset in data sheet */ #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */ #define HHI_NAND_CLK_CNTL 0x25c /* 0x97 offset in data sheet */ #define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ @@ -139,8 +140,14 @@ #define CLKID_HDMI_SYS_SEL 172 #define CLKID_HDMI_SYS_DIV 173 #define CLKID_HDMI_SYS 174 +#define CLKID_MALI_0_SEL 175 +#define CLKID_MALI_0_DIV 176 +#define CLKID_MALI_0 177 +#define CLKID_MALI_1_SEL 178 +#define CLKID_MALI_1_DIV 179 +#define CLKID_MALI_1 180 -#define CLK_NR_CLKS 175 +#define CLK_NR_CLKS 181 /* * include the CLKID and RESETID that have -- cgit v1.2.3 From f5fd9fd4000984f19db689282054953981a50534 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Jul 2018 18:00:18 +0300 Subject: drm/etnaviv: fix some off by one bugs The ->nr_signal is the supposed to be the number of elements in the ->signal array. There was one place where it was 5 but it was supposed to be 4. That looks like a copy and paste bug. There were also two checks that were off by one. Fixes: 9e2c2e273012 ("drm/etnaviv: add infrastructure to query perf counter") Signed-off-by: Dan Carpenter Reviewed-by: Christian Gmeiner Tested-by: Christian Gmeiner Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_perfmon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c b/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c index 9980d81a26e3..4227a4006c34 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c @@ -113,7 +113,7 @@ static const struct etnaviv_pm_domain doms_3d[] = { .name = "PE", .profile_read = VIVS_MC_PROFILE_PE_READ, .profile_config = VIVS_MC_PROFILE_CONFIG0, - .nr_signals = 5, + .nr_signals = 4, .signal = (const struct etnaviv_pm_signal[]) { { "PIXEL_COUNT_KILLED_BY_COLOR_PIPE", @@ -435,7 +435,7 @@ int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu, dom = meta->domains + signal->domain; - if (signal->iter > dom->nr_signals) + if (signal->iter >= dom->nr_signals) return -EINVAL; sig = &dom->signal[signal->iter]; @@ -461,7 +461,7 @@ int etnaviv_pm_req_validate(const struct drm_etnaviv_gem_submit_pmr *r, dom = meta->domains + r->domain; - if (r->signal > dom->nr_signals) + if (r->signal >= dom->nr_signals) return -EINVAL; return 0; -- cgit v1.2.3 From 72ac64b84b2ecb5c980354a189018ede14d61035 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 23 Nov 2018 16:26:04 +0100 Subject: drm/etnaviv: move job context pointer to etnaviv_gem_submit The context isn't really related to the cmdbuf, but is a property of the job. This has been missed when moving to a properly refcounted etnaviv_gem_submit. Signed-off-by: Lucas Stach Reviewed-by: Christian Gmeiner --- drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h | 2 -- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 1 + drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h index acb68c698363..4d5d1a77eb2a 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h @@ -15,8 +15,6 @@ struct etnaviv_perfmon_request; struct etnaviv_cmdbuf { /* suballocator this cmdbuf is allocated from */ struct etnaviv_cmdbuf_suballoc *suballoc; - /* user context key, must be unique between all active users */ - struct etnaviv_file_private *ctx; /* cmdbuf properties */ int suballoc_offset; void *vaddr; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index 76079c2291f8..f0abb744ef95 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -95,6 +95,7 @@ struct etnaviv_gem_submit_bo { struct etnaviv_gem_submit { struct drm_sched_job sched_job; struct kref refcount; + struct etnaviv_file_private *ctx; struct etnaviv_gpu *gpu; struct dma_fence *out_fence, *in_fence; int out_fence_id; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 30875f8f2933..b2fe3446bfbc 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -506,7 +506,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto err_submit_objects; - submit->cmdbuf.ctx = file->driver_priv; + submit->ctx = file->driver_priv; submit->exec_state = args->exec_state; submit->flags = args->flags; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 49a6763693f1..7e4f550dde5b 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -150,7 +150,7 @@ int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, mutex_lock(&submit->gpu->fence_lock); ret = drm_sched_job_init(&submit->sched_job, sched_entity, - submit->cmdbuf.ctx); + submit->ctx); if (ret) goto out_unlock; -- cgit v1.2.3 From c23fdef891acc3891b2885f29d9f48193ecc865a Mon Sep 17 00:00:00 2001 From: Clark Wang Date: Mon, 7 Jan 2019 07:47:38 +0000 Subject: spi: lpspi: Improve the stability of lpspi data transmission Use SR_TDF to judge if need to send data, and SR_FCF is to judge if transmission end and to replace the waiting after transmission end. This waiting has no actual meaning, for module will set the FCF flag at the real end. The changes of interrupt flag and ISR function reduce the times of calling ISR. The use of the FCF flag improves the stability of the data transmission. These two points generally improve the data transfer speed of lpspi, especially when it is set to slave mode it can support higher transfer speed of the host. After making these changes, there is no need to use fsl_lpspi_txfifo_empty(), so remove it. Signed-off-by: Clark Wang Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 61 +++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 08dcc3c22e88..ba207931e209 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -49,9 +49,11 @@ #define CR_RST BIT(1) #define CR_MEN BIT(0) #define SR_TCF BIT(10) +#define SR_FCF BIT(9) #define SR_RDF BIT(1) #define SR_TDF BIT(0) #define IER_TCIE BIT(10) +#define IER_FCIE BIT(9) #define IER_RDIE BIT(1) #define IER_TDIE BIT(0) #define CFGR1_PCSCFG BIT(27) @@ -161,28 +163,10 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller) return 0; } -static int fsl_lpspi_txfifo_empty(struct fsl_lpspi_data *fsl_lpspi) -{ - u32 txcnt; - unsigned long orig_jiffies = jiffies; - - do { - txcnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff; - - if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { - dev_dbg(fsl_lpspi->dev, "txfifo empty timeout\n"); - return -ETIMEDOUT; - } - cond_resched(); - - } while (txcnt); - - return 0; -} - static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi) { u8 txfifo_cnt; + u32 temp; txfifo_cnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff; @@ -193,9 +177,15 @@ static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi) txfifo_cnt++; } - if (!fsl_lpspi->remain && (txfifo_cnt < fsl_lpspi->txfifosize)) - writel(0, fsl_lpspi->base + IMX7ULP_TDR); - else + if (txfifo_cnt < fsl_lpspi->txfifosize) { + if (!fsl_lpspi->is_slave) { + temp = readl(fsl_lpspi->base + IMX7ULP_TCR); + temp &= ~TCR_CONTC; + writel(temp, fsl_lpspi->base + IMX7ULP_TCR); + } + + fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE); + } else fsl_lpspi_intctrl(fsl_lpspi, IER_TDIE); } @@ -391,12 +381,6 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller, if (ret) return ret; - ret = fsl_lpspi_txfifo_empty(fsl_lpspi); - if (ret) - return ret; - - fsl_lpspi_read_rx_fifo(fsl_lpspi); - return 0; } @@ -408,7 +392,6 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller, struct spi_device *spi = msg->spi; struct spi_transfer *xfer; bool is_first_xfer = true; - u32 temp; int ret = 0; msg->status = 0; @@ -428,13 +411,6 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller, } complete: - if (!fsl_lpspi->is_slave) { - /* de-assert SS, then finalize current message */ - temp = readl(fsl_lpspi->base + IMX7ULP_TCR); - temp &= ~TCR_CONTC; - writel(temp, fsl_lpspi->base + IMX7ULP_TCR); - } - msg->status = ret; spi_finalize_current_message(controller); @@ -443,20 +419,23 @@ complete: static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id) { + u32 temp_SR, temp_IER; struct fsl_lpspi_data *fsl_lpspi = dev_id; - u32 temp; + temp_IER = readl(fsl_lpspi->base + IMX7ULP_IER); fsl_lpspi_intctrl(fsl_lpspi, 0); - temp = readl(fsl_lpspi->base + IMX7ULP_SR); + temp_SR = readl(fsl_lpspi->base + IMX7ULP_SR); fsl_lpspi_read_rx_fifo(fsl_lpspi); - if (temp & SR_TDF) { + if ((temp_SR & SR_TDF) && (temp_IER & IER_TDIE)) { fsl_lpspi_write_tx_fifo(fsl_lpspi); + return IRQ_HANDLED; + } - if (!fsl_lpspi->remain) + if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) { + writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR); complete(&fsl_lpspi->xfer_done); - return IRQ_HANDLED; } -- cgit v1.2.3 From 6a130448498c151d31f1fb6f3003f5cf37b829e0 Mon Sep 17 00:00:00 2001 From: Clark Wang Date: Mon, 7 Jan 2019 07:47:41 +0000 Subject: spi: lpspi: Fix wrong transmission when don't use CONT Add judgment on SR_MBF and FSR_RXCOUNT. In PIO mode, if don't use CONT to keep cs selected in one transfer, the transfer will go wrong. FCIE will be set after one frame transfer finish. If use CONT, the frame refer to the whole data in one transfer. If don't use CONT, the frame refer to one byte of whole data. This will cause the transfer ending early. This patch add a register reading in isr function, it might lead to a slight decrease in the max transmission speed in PIO mode. Signed-off-by: Clark Wang Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index ba207931e209..d0b2d551cc43 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -48,6 +48,7 @@ #define CR_RTF BIT(8) #define CR_RST BIT(1) #define CR_MEN BIT(0) +#define SR_MBF BIT(24) #define SR_TCF BIT(10) #define SR_FCF BIT(9) #define SR_RDF BIT(1) @@ -61,6 +62,7 @@ #define CFGR1_PCSPOL BIT(8) #define CFGR1_NOSTALL BIT(3) #define CFGR1_MASTER BIT(0) +#define FSR_RXCOUNT (BIT(16)|BIT(17)|BIT(18)) #define RSR_RXEMPTY BIT(1) #define TCR_CPOL BIT(31) #define TCR_CPHA BIT(30) @@ -433,6 +435,13 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id) return IRQ_HANDLED; } + if (temp_SR & SR_MBF || + readl(fsl_lpspi->base + IMX7ULP_FSR) & FSR_RXCOUNT) { + writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR); + fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE); + return IRQ_HANDLED; + } + if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) { writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR); complete(&fsl_lpspi->xfer_done); -- cgit v1.2.3 From a15dc3d657fa2df08d1adbed926050314b5f4ba7 Mon Sep 17 00:00:00 2001 From: Clark Wang Date: Mon, 7 Jan 2019 07:47:43 +0000 Subject: spi: lpspi: Fix CLK pin becomes low before one transfer Remove Reset operation in fsl_lpspi_config(). This RST may cause both CLK and CS pins go from high to low level under cs-gpio mode. Add fsl_lpspi_reset() function after one message transfer to clear all flags in use. Signed-off-by: Clark Wang Reviewed-by: Fugang Duan Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index d0b2d551cc43..391863914043 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -268,10 +268,6 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi) u32 temp; int ret; - temp = CR_RST; - writel(temp, fsl_lpspi->base + IMX7ULP_CR); - writel(0, fsl_lpspi->base + IMX7ULP_CR); - if (!fsl_lpspi->is_slave) { ret = fsl_lpspi_set_bitrate(fsl_lpspi); if (ret) @@ -362,6 +358,24 @@ static int fsl_lpspi_wait_for_completion(struct spi_controller *controller) return 0; } +static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi) +{ + u32 temp; + + /* Disable all interrupt */ + fsl_lpspi_intctrl(fsl_lpspi, 0); + + /* W1C for all flags in SR */ + temp = 0x3F << 8; + writel(temp, fsl_lpspi->base + IMX7ULP_SR); + + /* Clear FIFO and disable module */ + temp = CR_RRF | CR_RTF; + writel(temp, fsl_lpspi->base + IMX7ULP_CR); + + return 0; +} + static int fsl_lpspi_transfer_one(struct spi_controller *controller, struct spi_device *spi, struct spi_transfer *t) @@ -383,6 +397,8 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller, if (ret) return ret; + fsl_lpspi_reset(fsl_lpspi); + return 0; } -- cgit v1.2.3 From d6afa2bed00486767fd5f3255cc89c05ccb70c0a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 5 Jan 2019 11:28:17 +0800 Subject: regulator: bcm590xx: Fix .enable_reg for BCM590XX_REG_VSR Current implementation missed the case BCM590XX_REG_VSR, so bcm590xx_get_enable_register() returns 0 when id is BCM590XX_REG_VSR. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/bcm590xx-regulator.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index 92d6d7b10cf7..e49c0a7d5dd5 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -242,8 +242,12 @@ static int bcm590xx_get_enable_register(int id) case BCM590XX_REG_SDSR2: reg = BCM590XX_SDSR2PMCTRL1; break; + case BCM590XX_REG_VSR: + reg = BCM590XX_VSRPMCTRL1; + break; case BCM590XX_REG_VBUS: reg = BCM590XX_OTG_CTRL; + break; } -- cgit v1.2.3 From f2fd71db12f8269a0384321c3c71a9312c66b415 Mon Sep 17 00:00:00 2001 From: Suwan Kim Date: Mon, 7 Jan 2019 23:21:11 +0900 Subject: usb: core: Simplify return value of usb_get_configuration() It is better to initialize the return value "result" to -ENOMEM than to 0. And because "result" takes the return value of usb_parse_configuration() which returns 0 for success, setting "result" to 0 at before and after of the for loop is unnecessary. Signed-off-by: Suwan Kim Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 7b5cb28ffb35..4a0945c04b4c 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -800,13 +800,12 @@ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = 0; + int result = -ENOMEM; unsigned int cfgno, length; unsigned char *bigbuffer; struct usb_config_descriptor *desc; cfgno = 0; - result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -832,7 +831,6 @@ int usb_get_configuration(struct usb_device *dev) if (!desc) goto err2; - result = 0; for (; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ @@ -889,7 +887,6 @@ int usb_get_configuration(struct usb_device *dev) goto err; } } - result = 0; err: kfree(desc); -- cgit v1.2.3 From d1ab1b842073b148a61e65c747826379e9c3e08e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 4 Jan 2019 17:43:49 +0000 Subject: usb: host: u132-hcd: fix a couple of indentation issues There are two statements that are indented incorrectly and need to be moved to a new line. Fix these. Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 5b8a3d9530c4..934584f0a20a 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2477,7 +2477,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } urb->error_count = 0; + } + urb->error_count = 0; usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { @@ -2982,7 +2983,8 @@ static int u132_remove(struct platform_device *pdev) while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; u132_ring_cancel_work(u132, ring); - } while (endps-- > 0) { + } + while (endps-- > 0) { struct u132_endp *endp = u132->endp[endps]; if (endp) u132_endp_cancel_work(u132, endp); -- cgit v1.2.3 From 8a1dbc8d91d3d1602282c7e6b4222c7759c916fa Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Wed, 2 Jan 2019 09:33:56 +0800 Subject: usb: devio: update max count of DPs per interval for ISOC The failure happened when I tried to send up to 96DPs per an interval for SSP ISOC transations by libusb, this is used to verify SSP ISOC function of USB3 GEN2 controller, so update it as 96DPs. (refer usb3.1r1.0 section 8.12.6 Isochronous Transactions) Signed-off-by: Chunfeng Yun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index d65566341dd1..a12f2ce8df90 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1564,12 +1564,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb } for (totlen = u = 0; u < number_of_packets; u++) { /* - * arbitrary limit need for USB 3.0 - * bMaxBurst (0~15 allowed, 1~16 packets) - * bmAttributes (bit 1:0, mult 0~2, 1~3 packets) - * sizemax: 1024 * 16 * 3 = 49152 + * arbitrary limit need for USB 3.1 Gen2 + * sizemax: 96 DPs at SSP, 96 * 1024 = 98304 */ - if (isopkt[u].length > 49152) { + if (isopkt[u].length > 98304) { ret = -EINVAL; goto error; } -- cgit v1.2.3 From 00553f322b7ac2a4e774e36fb633265f43651a7c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 30 Dec 2018 16:53:08 +0100 Subject: usb: gadget: udc: reduce indentation Delete tab aligning a statement with the right hand side of a preceding assignment rather than the left hand side. Found with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/snps_udc_core.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index d4da47f4f6f4..3fcded31405a 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -947,15 +947,14 @@ static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp) UDC_DMA_STP_STS_BS_HOST_READY, UDC_DMA_STP_STS_BS); - - /* clear NAK by writing CNAK */ - if (ep->naking) { - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->naking = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } + /* clear NAK by writing CNAK */ + if (ep->naking) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } } -- cgit v1.2.3 From 84d043185dbe0d1b4f6db575bd91c834d37e2f78 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Mon, 7 Jan 2019 09:29:47 +0000 Subject: spi: Add a driver for the Freescale/NXP QuadSPI controller This driver is derived from the SPI NOR driver at mtd/spi-nor/fsl-quadspi.c. It uses the new SPI memory interface of the SPI framework to issue flash memory operations to up to four connected flash chips (2 buses with 2 CS each). The controller does not support generic SPI messages. This patch also disables the build of the "old" driver and reuses its Kconfig option CONFIG_SPI_FSL_QUADSPI to replace it. Signed-off-by: Frieder Schrempf Acked-by: Han Xu Reviewed-by: Yogesh Gaur Tested-by: Yogesh Gaur Tested-by: Han Xu Reviewed-by: Boris Brezillon Signed-off-by: Mark Brown --- drivers/mtd/spi-nor/Kconfig | 9 - drivers/mtd/spi-nor/Makefile | 1 - drivers/spi/Kconfig | 11 + drivers/spi/Makefile | 1 + drivers/spi/spi-fsl-qspi.c | 966 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 978 insertions(+), 10 deletions(-) create mode 100644 drivers/spi/spi-fsl-qspi.c (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 44fe8018733c..b433e5f91069 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -50,15 +50,6 @@ config SPI_CADENCE_QUADSPI device with a Cadence QSPI controller and want to access the Flash as an MTD device. -config SPI_FSL_QUADSPI - tristate "Freescale Quad SPI controller" - depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST - depends on HAS_IOMEM - help - This enables support for the Quad SPI controller in master mode. - This controller does not support generic SPI. It only supports - SPI NOR. - config SPI_HISI_SFC tristate "Hisilicon SPI-NOR Flash Controller(SFC)" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index a552efd22958..2adedbe07662 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -2,7 +2,6 @@ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o -obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9f89cb134549..e22fc233ed07 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -268,6 +268,17 @@ config SPI_FSL_LPSPI help This enables Freescale i.MX LPSPI controllers in master mode. +config SPI_FSL_QUADSPI + tristate "Freescale QSPI controller" + depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST + depends on HAS_IOMEM + help + This enables support for the Quad SPI controller in master mode. + Up to four flash chips can be connected on two buses with two + chipselects each. + This controller does not support generic SPI messages. It only + supports the high-level SPI memory interface. + config SPI_GPIO tristate "GPIO-based bitbanging SPI Master" depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index f29627040dfb..2a857cb9aa81 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o obj-$(CONFIG_SPI_FSL_LPSPI) += spi-fsl-lpspi.o +obj-$(CONFIG_SPI_FSL_QUADSPI) += spi-fsl-qspi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c new file mode 100644 index 000000000000..f0a340026ba4 --- /dev/null +++ b/drivers/spi/spi-fsl-qspi.c @@ -0,0 +1,966 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Freescale QuadSPI driver. + * + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * Copyright (C) 2018 Bootlin + * Copyright (C) 2018 exceet electronics GmbH + * Copyright (C) 2018 Kontron Electronics GmbH + * + * Transition to SPI MEM interface: + * Authors: + * Boris Brezillion + * Frieder Schrempf + * Yogesh Gaur + * Suresh Gupta + * + * Based on the original fsl-quadspi.c spi-nor driver: + * Author: Freescale Semiconductor, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * The driver only uses one single LUT entry, that is updated on + * each call of exec_op(). Index 0 is preset at boot with a basic + * read operation, so let's use the last entry (15). + */ +#define SEQID_LUT 15 + +/* Registers used by the driver */ +#define QUADSPI_MCR 0x00 +#define QUADSPI_MCR_RESERVED_MASK GENMASK(19, 16) +#define QUADSPI_MCR_MDIS_MASK BIT(14) +#define QUADSPI_MCR_CLR_TXF_MASK BIT(11) +#define QUADSPI_MCR_CLR_RXF_MASK BIT(10) +#define QUADSPI_MCR_DDR_EN_MASK BIT(7) +#define QUADSPI_MCR_END_CFG_MASK GENMASK(3, 2) +#define QUADSPI_MCR_SWRSTHD_MASK BIT(1) +#define QUADSPI_MCR_SWRSTSD_MASK BIT(0) + +#define QUADSPI_IPCR 0x08 +#define QUADSPI_IPCR_SEQID(x) ((x) << 24) + +#define QUADSPI_BUF3CR 0x1c +#define QUADSPI_BUF3CR_ALLMST_MASK BIT(31) +#define QUADSPI_BUF3CR_ADATSZ(x) ((x) << 8) +#define QUADSPI_BUF3CR_ADATSZ_MASK GENMASK(15, 8) + +#define QUADSPI_BFGENCR 0x20 +#define QUADSPI_BFGENCR_SEQID(x) ((x) << 12) + +#define QUADSPI_BUF0IND 0x30 +#define QUADSPI_BUF1IND 0x34 +#define QUADSPI_BUF2IND 0x38 +#define QUADSPI_SFAR 0x100 + +#define QUADSPI_SMPR 0x108 +#define QUADSPI_SMPR_DDRSMP_MASK GENMASK(18, 16) +#define QUADSPI_SMPR_FSDLY_MASK BIT(6) +#define QUADSPI_SMPR_FSPHS_MASK BIT(5) +#define QUADSPI_SMPR_HSENA_MASK BIT(0) + +#define QUADSPI_RBCT 0x110 +#define QUADSPI_RBCT_WMRK_MASK GENMASK(4, 0) +#define QUADSPI_RBCT_RXBRD_USEIPS BIT(8) + +#define QUADSPI_TBDR 0x154 + +#define QUADSPI_SR 0x15c +#define QUADSPI_SR_IP_ACC_MASK BIT(1) +#define QUADSPI_SR_AHB_ACC_MASK BIT(2) + +#define QUADSPI_FR 0x160 +#define QUADSPI_FR_TFF_MASK BIT(0) + +#define QUADSPI_SPTRCLR 0x16c +#define QUADSPI_SPTRCLR_IPPTRC BIT(8) +#define QUADSPI_SPTRCLR_BFPTRC BIT(0) + +#define QUADSPI_SFA1AD 0x180 +#define QUADSPI_SFA2AD 0x184 +#define QUADSPI_SFB1AD 0x188 +#define QUADSPI_SFB2AD 0x18c +#define QUADSPI_RBDR(x) (0x200 + ((x) * 4)) + +#define QUADSPI_LUTKEY 0x300 +#define QUADSPI_LUTKEY_VALUE 0x5AF05AF0 + +#define QUADSPI_LCKCR 0x304 +#define QUADSPI_LCKER_LOCK BIT(0) +#define QUADSPI_LCKER_UNLOCK BIT(1) + +#define QUADSPI_RSER 0x164 +#define QUADSPI_RSER_TFIE BIT(0) + +#define QUADSPI_LUT_BASE 0x310 +#define QUADSPI_LUT_OFFSET (SEQID_LUT * 4 * 4) +#define QUADSPI_LUT_REG(idx) \ + (QUADSPI_LUT_BASE + QUADSPI_LUT_OFFSET + (idx) * 4) + +/* Instruction set for the LUT register */ +#define LUT_STOP 0 +#define LUT_CMD 1 +#define LUT_ADDR 2 +#define LUT_DUMMY 3 +#define LUT_MODE 4 +#define LUT_MODE2 5 +#define LUT_MODE4 6 +#define LUT_FSL_READ 7 +#define LUT_FSL_WRITE 8 +#define LUT_JMP_ON_CS 9 +#define LUT_ADDR_DDR 10 +#define LUT_MODE_DDR 11 +#define LUT_MODE2_DDR 12 +#define LUT_MODE4_DDR 13 +#define LUT_FSL_READ_DDR 14 +#define LUT_FSL_WRITE_DDR 15 +#define LUT_DATA_LEARN 16 + +/* + * The PAD definitions for LUT register. + * + * The pad stands for the number of IO lines [0:3]. + * For example, the quad read needs four IO lines, + * so you should use LUT_PAD(4). + */ +#define LUT_PAD(x) (fls(x) - 1) + +/* + * Macro for constructing the LUT entries with the following + * register layout: + * + * --------------------------------------------------- + * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 | + * --------------------------------------------------- + */ +#define LUT_DEF(idx, ins, pad, opr) \ + ((((ins) << 10) | ((pad) << 8) | (opr)) << (((idx) % 2) * 16)) + +/* Controller needs driver to swap endianness */ +#define QUADSPI_QUIRK_SWAP_ENDIAN BIT(0) + +/* Controller needs 4x internal clock */ +#define QUADSPI_QUIRK_4X_INT_CLK BIT(1) + +/* + * TKT253890, the controller needs the driver to fill the txfifo with + * 16 bytes at least to trigger a data transfer, even though the extra + * data won't be transferred. + */ +#define QUADSPI_QUIRK_TKT253890 BIT(2) + +/* TKT245618, the controller cannot wake up from wait mode */ +#define QUADSPI_QUIRK_TKT245618 BIT(3) + +/* + * Controller adds QSPI_AMBA_BASE (base address of the mapped memory) + * internally. No need to add it when setting SFXXAD and SFAR registers + */ +#define QUADSPI_QUIRK_BASE_INTERNAL BIT(4) + +struct fsl_qspi_devtype_data { + unsigned int rxfifo; + unsigned int txfifo; + unsigned int ahb_buf_size; + unsigned int quirks; + bool little_endian; +}; + +static const struct fsl_qspi_devtype_data vybrid_data = { + .rxfifo = SZ_128, + .txfifo = SZ_64, + .ahb_buf_size = SZ_1K, + .quirks = QUADSPI_QUIRK_SWAP_ENDIAN, + .little_endian = true, +}; + +static const struct fsl_qspi_devtype_data imx6sx_data = { + .rxfifo = SZ_128, + .txfifo = SZ_512, + .ahb_buf_size = SZ_1K, + .quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618, + .little_endian = true, +}; + +static const struct fsl_qspi_devtype_data imx7d_data = { + .rxfifo = SZ_512, + .txfifo = SZ_512, + .ahb_buf_size = SZ_1K, + .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK, + .little_endian = true, +}; + +static const struct fsl_qspi_devtype_data imx6ul_data = { + .rxfifo = SZ_128, + .txfifo = SZ_512, + .ahb_buf_size = SZ_1K, + .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK, + .little_endian = true, +}; + +static const struct fsl_qspi_devtype_data ls1021a_data = { + .rxfifo = SZ_128, + .txfifo = SZ_64, + .ahb_buf_size = SZ_1K, + .quirks = 0, + .little_endian = false, +}; + +static const struct fsl_qspi_devtype_data ls2080a_data = { + .rxfifo = SZ_128, + .txfifo = SZ_64, + .ahb_buf_size = SZ_1K, + .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_BASE_INTERNAL, + .little_endian = true, +}; + +struct fsl_qspi { + void __iomem *iobase; + void __iomem *ahb_addr; + u32 memmap_phy; + struct clk *clk, *clk_en; + struct device *dev; + struct completion c; + const struct fsl_qspi_devtype_data *devtype_data; + struct mutex lock; + struct pm_qos_request pm_qos_req; + int selected; +}; + +static inline int needs_swap_endian(struct fsl_qspi *q) +{ + return q->devtype_data->quirks & QUADSPI_QUIRK_SWAP_ENDIAN; +} + +static inline int needs_4x_clock(struct fsl_qspi *q) +{ + return q->devtype_data->quirks & QUADSPI_QUIRK_4X_INT_CLK; +} + +static inline int needs_fill_txfifo(struct fsl_qspi *q) +{ + return q->devtype_data->quirks & QUADSPI_QUIRK_TKT253890; +} + +static inline int needs_wakeup_wait_mode(struct fsl_qspi *q) +{ + return q->devtype_data->quirks & QUADSPI_QUIRK_TKT245618; +} + +static inline int needs_amba_base_offset(struct fsl_qspi *q) +{ + return !(q->devtype_data->quirks & QUADSPI_QUIRK_BASE_INTERNAL); +} + +/* + * An IC bug makes it necessary to rearrange the 32-bit data. + * Later chips, such as IMX6SLX, have fixed this bug. + */ +static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a) +{ + return needs_swap_endian(q) ? __swab32(a) : a; +} + +/* + * R/W functions for big- or little-endian registers: + * The QSPI controller's endianness is independent of + * the CPU core's endianness. So far, although the CPU + * core is little-endian the QSPI controller can use + * big-endian or little-endian. + */ +static void qspi_writel(struct fsl_qspi *q, u32 val, void __iomem *addr) +{ + if (q->devtype_data->little_endian) + iowrite32(val, addr); + else + iowrite32be(val, addr); +} + +static u32 qspi_readl(struct fsl_qspi *q, void __iomem *addr) +{ + if (q->devtype_data->little_endian) + return ioread32(addr); + + return ioread32be(addr); +} + +static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id) +{ + struct fsl_qspi *q = dev_id; + u32 reg; + + /* clear interrupt */ + reg = qspi_readl(q, q->iobase + QUADSPI_FR); + qspi_writel(q, reg, q->iobase + QUADSPI_FR); + + if (reg & QUADSPI_FR_TFF_MASK) + complete(&q->c); + + dev_dbg(q->dev, "QUADSPI_FR : 0x%.8x:0x%.8x\n", 0, reg); + return IRQ_HANDLED; +} + +static int fsl_qspi_check_buswidth(struct fsl_qspi *q, u8 width) +{ + switch (width) { + case 1: + case 2: + case 4: + return 0; + } + + return -ENOTSUPP; +} + +static bool fsl_qspi_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master); + int ret; + + ret = fsl_qspi_check_buswidth(q, op->cmd.buswidth); + + if (op->addr.nbytes) + ret |= fsl_qspi_check_buswidth(q, op->addr.buswidth); + + if (op->dummy.nbytes) + ret |= fsl_qspi_check_buswidth(q, op->dummy.buswidth); + + if (op->data.nbytes) + ret |= fsl_qspi_check_buswidth(q, op->data.buswidth); + + if (ret) + return false; + + /* + * The number of instructions needed for the op, needs + * to fit into a single LUT entry. + */ + if (op->addr.nbytes + + (op->dummy.nbytes ? 1:0) + + (op->data.nbytes ? 1:0) > 6) + return false; + + /* Max 64 dummy clock cycles supported */ + if (op->dummy.nbytes && + (op->dummy.nbytes * 8 / op->dummy.buswidth > 64)) + return false; + + /* Max data length, check controller limits and alignment */ + if (op->data.dir == SPI_MEM_DATA_IN && + (op->data.nbytes > q->devtype_data->ahb_buf_size || + (op->data.nbytes > q->devtype_data->rxfifo - 4 && + !IS_ALIGNED(op->data.nbytes, 8)))) + return false; + + if (op->data.dir == SPI_MEM_DATA_OUT && + op->data.nbytes > q->devtype_data->txfifo) + return false; + + return true; +} + +static void fsl_qspi_prepare_lut(struct fsl_qspi *q, + const struct spi_mem_op *op) +{ + void __iomem *base = q->iobase; + u32 lutval[4] = {}; + int lutidx = 1, i; + + lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth), + op->cmd.opcode); + + /* + * For some unknown reason, using LUT_ADDR doesn't work in some + * cases (at least with only one byte long addresses), so + * let's use LUT_MODE to write the address bytes one by one + */ + for (i = 0; i < op->addr.nbytes; i++) { + u8 addrbyte = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); + + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_MODE, + LUT_PAD(op->addr.buswidth), + addrbyte); + lutidx++; + } + + if (op->dummy.nbytes) { + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_DUMMY, + LUT_PAD(op->dummy.buswidth), + op->dummy.nbytes * 8 / + op->dummy.buswidth); + lutidx++; + } + + if (op->data.nbytes) { + lutval[lutidx / 2] |= LUT_DEF(lutidx, + op->data.dir == SPI_MEM_DATA_IN ? + LUT_FSL_READ : LUT_FSL_WRITE, + LUT_PAD(op->data.buswidth), + 0); + lutidx++; + } + + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_STOP, 0, 0); + + /* unlock LUT */ + qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); + qspi_writel(q, QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR); + + /* fill LUT */ + for (i = 0; i < ARRAY_SIZE(lutval); i++) + qspi_writel(q, lutval[i], base + QUADSPI_LUT_REG(i)); + + /* lock LUT */ + qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); + qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR); +} + +static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q) +{ + int ret; + + ret = clk_prepare_enable(q->clk_en); + if (ret) + return ret; + + ret = clk_prepare_enable(q->clk); + if (ret) { + clk_disable_unprepare(q->clk_en); + return ret; + } + + if (needs_wakeup_wait_mode(q)) + pm_qos_add_request(&q->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0); + + return 0; +} + +static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q) +{ + if (needs_wakeup_wait_mode(q)) + pm_qos_remove_request(&q->pm_qos_req); + + clk_disable_unprepare(q->clk); + clk_disable_unprepare(q->clk_en); +} + +/* + * If we have changed the content of the flash by writing or erasing, or if we + * read from flash with a different offset into the page buffer, we need to + * invalidate the AHB buffer. If we do not do so, we may read out the wrong + * data. The spec tells us reset the AHB domain and Serial Flash domain at + * the same time. + */ +static void fsl_qspi_invalidate(struct fsl_qspi *q) +{ + u32 reg; + + reg = qspi_readl(q, q->iobase + QUADSPI_MCR); + reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK; + qspi_writel(q, reg, q->iobase + QUADSPI_MCR); + + /* + * The minimum delay : 1 AHB + 2 SFCK clocks. + * Delay 1 us is enough. + */ + udelay(1); + + reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK); + qspi_writel(q, reg, q->iobase + QUADSPI_MCR); +} + +static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi) +{ + unsigned long rate = spi->max_speed_hz; + int ret; + + if (q->selected == spi->chip_select) + return; + + if (needs_4x_clock(q)) + rate *= 4; + + fsl_qspi_clk_disable_unprep(q); + + ret = clk_set_rate(q->clk, rate); + if (ret) + return; + + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return; + + q->selected = spi->chip_select; + + fsl_qspi_invalidate(q); +} + +static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op) +{ + memcpy_fromio(op->data.buf.in, + q->ahb_addr + q->selected * q->devtype_data->ahb_buf_size, + op->data.nbytes); +} + +static void fsl_qspi_fill_txfifo(struct fsl_qspi *q, + const struct spi_mem_op *op) +{ + void __iomem *base = q->iobase; + int i; + u32 val; + + for (i = 0; i < ALIGN_DOWN(op->data.nbytes, 4); i += 4) { + memcpy(&val, op->data.buf.out + i, 4); + val = fsl_qspi_endian_xchg(q, val); + qspi_writel(q, val, base + QUADSPI_TBDR); + } + + if (i < op->data.nbytes) { + memcpy(&val, op->data.buf.out + i, op->data.nbytes - i); + val = fsl_qspi_endian_xchg(q, val); + qspi_writel(q, val, base + QUADSPI_TBDR); + } + + if (needs_fill_txfifo(q)) { + for (i = op->data.nbytes; i < 16; i += 4) + qspi_writel(q, 0, base + QUADSPI_TBDR); + } +} + +static void fsl_qspi_read_rxfifo(struct fsl_qspi *q, + const struct spi_mem_op *op) +{ + void __iomem *base = q->iobase; + int i; + u8 *buf = op->data.buf.in; + u32 val; + + for (i = 0; i < ALIGN_DOWN(op->data.nbytes, 4); i += 4) { + val = qspi_readl(q, base + QUADSPI_RBDR(i / 4)); + val = fsl_qspi_endian_xchg(q, val); + memcpy(buf + i, &val, 4); + } + + if (i < op->data.nbytes) { + val = qspi_readl(q, base + QUADSPI_RBDR(i / 4)); + val = fsl_qspi_endian_xchg(q, val); + memcpy(buf + i, &val, op->data.nbytes - i); + } +} + +static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) +{ + void __iomem *base = q->iobase; + int err = 0; + + init_completion(&q->c); + + /* + * Always start the sequence at the same index since we update + * the LUT at each exec_op() call. And also specify the DATA + * length, since it's has not been specified in the LUT. + */ + qspi_writel(q, op->data.nbytes | QUADSPI_IPCR_SEQID(SEQID_LUT), + base + QUADSPI_IPCR); + + /* Wait for the interrupt. */ + if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) + err = -ETIMEDOUT; + + if (!err && op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN) + fsl_qspi_read_rxfifo(q, op); + + return err; +} + +static int fsl_qspi_readl_poll_tout(struct fsl_qspi *q, void __iomem *base, + u32 mask, u32 delay_us, u32 timeout_us) +{ + u32 reg; + + if (!q->devtype_data->little_endian) + mask = (u32)cpu_to_be32(mask); + + return readl_poll_timeout(base, reg, !(reg & mask), delay_us, + timeout_us); +} + +static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master); + void __iomem *base = q->iobase; + u32 addr_offset = 0; + int err = 0; + + mutex_lock(&q->lock); + + /* wait for the controller being ready */ + fsl_qspi_readl_poll_tout(q, base + QUADSPI_SR, (QUADSPI_SR_IP_ACC_MASK | + QUADSPI_SR_AHB_ACC_MASK), 10, 1000); + + fsl_qspi_select_mem(q, mem->spi); + + if (needs_amba_base_offset(q)) + addr_offset = q->memmap_phy; + + qspi_writel(q, + q->selected * q->devtype_data->ahb_buf_size + addr_offset, + base + QUADSPI_SFAR); + + qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) | + QUADSPI_MCR_CLR_RXF_MASK | QUADSPI_MCR_CLR_TXF_MASK, + base + QUADSPI_MCR); + + qspi_writel(q, QUADSPI_SPTRCLR_BFPTRC | QUADSPI_SPTRCLR_IPPTRC, + base + QUADSPI_SPTRCLR); + + fsl_qspi_prepare_lut(q, op); + + /* + * If we have large chunks of data, we read them through the AHB bus + * by accessing the mapped memory. In all other cases we use + * IP commands to access the flash. + */ + if (op->data.nbytes > (q->devtype_data->rxfifo - 4) && + op->data.dir == SPI_MEM_DATA_IN) { + fsl_qspi_read_ahb(q, op); + } else { + qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | + QUADSPI_RBCT_RXBRD_USEIPS, base + QUADSPI_RBCT); + + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) + fsl_qspi_fill_txfifo(q, op); + + err = fsl_qspi_do_op(q, op); + } + + /* Invalidate the data in the AHB buffer. */ + fsl_qspi_invalidate(q); + + mutex_unlock(&q->lock); + + return err; +} + +static int fsl_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master); + + if (op->data.dir == SPI_MEM_DATA_OUT) { + if (op->data.nbytes > q->devtype_data->txfifo) + op->data.nbytes = q->devtype_data->txfifo; + } else { + if (op->data.nbytes > q->devtype_data->ahb_buf_size) + op->data.nbytes = q->devtype_data->ahb_buf_size; + else if (op->data.nbytes > (q->devtype_data->rxfifo - 4)) + op->data.nbytes = ALIGN_DOWN(op->data.nbytes, 8); + } + + return 0; +} + +static int fsl_qspi_default_setup(struct fsl_qspi *q) +{ + void __iomem *base = q->iobase; + u32 reg, addr_offset = 0; + int ret; + + /* disable and unprepare clock to avoid glitch pass to controller */ + fsl_qspi_clk_disable_unprep(q); + + /* the default frequency, we will change it later if necessary. */ + ret = clk_set_rate(q->clk, 66000000); + if (ret) + return ret; + + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return ret; + + /* Reset the module */ + qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK, + base + QUADSPI_MCR); + udelay(1); + + /* Disable the module */ + qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK, + base + QUADSPI_MCR); + + reg = qspi_readl(q, base + QUADSPI_SMPR); + qspi_writel(q, reg & ~(QUADSPI_SMPR_FSDLY_MASK + | QUADSPI_SMPR_FSPHS_MASK + | QUADSPI_SMPR_HSENA_MASK + | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR); + + /* We only use the buffer3 for AHB read */ + qspi_writel(q, 0, base + QUADSPI_BUF0IND); + qspi_writel(q, 0, base + QUADSPI_BUF1IND); + qspi_writel(q, 0, base + QUADSPI_BUF2IND); + + qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT), + q->iobase + QUADSPI_BFGENCR); + qspi_writel(q, QUADSPI_RBCT_WMRK_MASK, base + QUADSPI_RBCT); + qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK | + QUADSPI_BUF3CR_ADATSZ(q->devtype_data->ahb_buf_size / 8), + base + QUADSPI_BUF3CR); + + if (needs_amba_base_offset(q)) + addr_offset = q->memmap_phy; + + /* + * In HW there can be a maximum of four chips on two buses with + * two chip selects on each bus. We use four chip selects in SW + * to differentiate between the four chips. + * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD, + * SFB2AD accordingly. + */ + qspi_writel(q, q->devtype_data->ahb_buf_size + addr_offset, + base + QUADSPI_SFA1AD); + qspi_writel(q, q->devtype_data->ahb_buf_size * 2 + addr_offset, + base + QUADSPI_SFA2AD); + qspi_writel(q, q->devtype_data->ahb_buf_size * 3 + addr_offset, + base + QUADSPI_SFB1AD); + qspi_writel(q, q->devtype_data->ahb_buf_size * 4 + addr_offset, + base + QUADSPI_SFB2AD); + + q->selected = -1; + + /* Enable the module */ + qspi_writel(q, QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK, + base + QUADSPI_MCR); + + /* clear all interrupt status */ + qspi_writel(q, 0xffffffff, q->iobase + QUADSPI_FR); + + /* enable the interrupt */ + qspi_writel(q, QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER); + + return 0; +} + +static const char *fsl_qspi_get_name(struct spi_mem *mem) +{ + struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master); + struct device *dev = &mem->spi->dev; + const char *name; + + /* + * In order to keep mtdparts compatible with the old MTD driver at + * mtd/spi-nor/fsl-quadspi.c, we set a custom name derived from the + * platform_device of the controller. + */ + if (of_get_available_child_count(q->dev->of_node) == 1) + return dev_name(q->dev); + + name = devm_kasprintf(dev, GFP_KERNEL, + "%s-%d", dev_name(q->dev), + mem->spi->chip_select); + + if (!name) { + dev_err(dev, "failed to get memory for custom flash name\n"); + return ERR_PTR(-ENOMEM); + } + + return name; +} + +static const struct spi_controller_mem_ops fsl_qspi_mem_ops = { + .adjust_op_size = fsl_qspi_adjust_op_size, + .supports_op = fsl_qspi_supports_op, + .exec_op = fsl_qspi_exec_op, + .get_name = fsl_qspi_get_name, +}; + +static int fsl_qspi_probe(struct platform_device *pdev) +{ + struct spi_controller *ctlr; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct resource *res; + struct fsl_qspi *q; + int ret; + + ctlr = spi_alloc_master(&pdev->dev, sizeof(*q)); + if (!ctlr) + return -ENOMEM; + + ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | + SPI_TX_DUAL | SPI_TX_QUAD; + + q = spi_controller_get_devdata(ctlr); + q->dev = dev; + q->devtype_data = of_device_get_match_data(dev); + if (!q->devtype_data) { + ret = -ENODEV; + goto err_put_ctrl; + } + + platform_set_drvdata(pdev, q); + + /* find the resources */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI"); + q->iobase = devm_ioremap_resource(dev, res); + if (IS_ERR(q->iobase)) { + ret = PTR_ERR(q->iobase); + goto err_put_ctrl; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "QuadSPI-memory"); + q->ahb_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(q->ahb_addr)) { + ret = PTR_ERR(q->ahb_addr); + goto err_put_ctrl; + } + + q->memmap_phy = res->start; + + /* find the clocks */ + q->clk_en = devm_clk_get(dev, "qspi_en"); + if (IS_ERR(q->clk_en)) { + ret = PTR_ERR(q->clk_en); + goto err_put_ctrl; + } + + q->clk = devm_clk_get(dev, "qspi"); + if (IS_ERR(q->clk)) { + ret = PTR_ERR(q->clk); + goto err_put_ctrl; + } + + ret = fsl_qspi_clk_prep_enable(q); + if (ret) { + dev_err(dev, "can not enable the clock\n"); + goto err_put_ctrl; + } + + /* find the irq */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "failed to get the irq: %d\n", ret); + goto err_disable_clk; + } + + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { + dev_err(dev, "failed to request irq: %d\n", ret); + goto err_disable_clk; + } + + mutex_init(&q->lock); + + ctlr->bus_num = -1; + ctlr->num_chipselect = 4; + ctlr->mem_ops = &fsl_qspi_mem_ops; + + fsl_qspi_default_setup(q); + + ctlr->dev.of_node = np; + + ret = spi_register_controller(ctlr); + if (ret) + goto err_destroy_mutex; + + return 0; + +err_destroy_mutex: + mutex_destroy(&q->lock); + +err_disable_clk: + fsl_qspi_clk_disable_unprep(q); + +err_put_ctrl: + spi_controller_put(ctlr); + + dev_err(dev, "Freescale QuadSPI probe failed\n"); + return ret; +} + +static int fsl_qspi_remove(struct platform_device *pdev) +{ + struct fsl_qspi *q = platform_get_drvdata(pdev); + + /* disable the hardware */ + qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); + qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER); + + fsl_qspi_clk_disable_unprep(q); + + mutex_destroy(&q->lock); + + return 0; +} + +static int fsl_qspi_suspend(struct device *dev) +{ + return 0; +} + +static int fsl_qspi_resume(struct device *dev) +{ + struct fsl_qspi *q = dev_get_drvdata(dev); + + fsl_qspi_default_setup(q); + + return 0; +} + +static const struct of_device_id fsl_qspi_dt_ids[] = { + { .compatible = "fsl,vf610-qspi", .data = &vybrid_data, }, + { .compatible = "fsl,imx6sx-qspi", .data = &imx6sx_data, }, + { .compatible = "fsl,imx7d-qspi", .data = &imx7d_data, }, + { .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, }, + { .compatible = "fsl,ls1021a-qspi", .data = &ls1021a_data, }, + { .compatible = "fsl,ls2080a-qspi", .data = &ls2080a_data, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); + +static const struct dev_pm_ops fsl_qspi_pm_ops = { + .suspend = fsl_qspi_suspend, + .resume = fsl_qspi_resume, +}; + +static struct platform_driver fsl_qspi_driver = { + .driver = { + .name = "fsl-quadspi", + .of_match_table = fsl_qspi_dt_ids, + .pm = &fsl_qspi_pm_ops, + }, + .probe = fsl_qspi_probe, + .remove = fsl_qspi_remove, +}; +module_platform_driver(fsl_qspi_driver); + +MODULE_DESCRIPTION("Freescale QuadSPI Controller Driver"); +MODULE_AUTHOR("Freescale Semiconductor Inc."); +MODULE_AUTHOR("Boris Brezillion "); +MODULE_AUTHOR("Frieder Schrempf "); +MODULE_AUTHOR("Yogesh Gaur "); +MODULE_AUTHOR("Suresh Gupta "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 50f1242c674226dd866949f24043f5a1076ee242 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Mon, 7 Jan 2019 09:29:53 +0000 Subject: mtd: fsl-quadspi: Remove the driver as it was replaced by spi-fsl-qspi.c There's a new driver using the SPI memory interface of the SPI framework at spi/spi-fsl-qspi.c, which can be used together with m25p80.c to replace the functionality of this SPI NOR driver. The new driver is already in use and this code is not compiled anymore, so let's remove it. Signed-off-by: Frieder Schrempf Acked-by: Han Xu Tested-by: Han Xu Acked-by: Boris Brezillon Signed-off-by: Mark Brown --- drivers/mtd/spi-nor/fsl-quadspi.c | 1224 ------------------------------------- 1 file changed, 1224 deletions(-) delete mode 100644 drivers/mtd/spi-nor/fsl-quadspi.c (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c deleted file mode 100644 index 1ff3430f82c8..000000000000 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ /dev/null @@ -1,1224 +0,0 @@ -/* - * Freescale QuadSPI driver. - * - * Copyright (C) 2013 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Controller needs driver to swap endian */ -#define QUADSPI_QUIRK_SWAP_ENDIAN (1 << 0) -/* Controller needs 4x internal clock */ -#define QUADSPI_QUIRK_4X_INT_CLK (1 << 1) -/* - * TKT253890, Controller needs driver to fill txfifo till 16 byte to - * trigger data transfer even though extern data will not transferred. - */ -#define QUADSPI_QUIRK_TKT253890 (1 << 2) -/* Controller cannot wake up from wait mode, TKT245618 */ -#define QUADSPI_QUIRK_TKT245618 (1 << 3) - -/* The registers */ -#define QUADSPI_MCR 0x00 -#define QUADSPI_MCR_RESERVED_SHIFT 16 -#define QUADSPI_MCR_RESERVED_MASK (0xF << QUADSPI_MCR_RESERVED_SHIFT) -#define QUADSPI_MCR_MDIS_SHIFT 14 -#define QUADSPI_MCR_MDIS_MASK (1 << QUADSPI_MCR_MDIS_SHIFT) -#define QUADSPI_MCR_CLR_TXF_SHIFT 11 -#define QUADSPI_MCR_CLR_TXF_MASK (1 << QUADSPI_MCR_CLR_TXF_SHIFT) -#define QUADSPI_MCR_CLR_RXF_SHIFT 10 -#define QUADSPI_MCR_CLR_RXF_MASK (1 << QUADSPI_MCR_CLR_RXF_SHIFT) -#define QUADSPI_MCR_DDR_EN_SHIFT 7 -#define QUADSPI_MCR_DDR_EN_MASK (1 << QUADSPI_MCR_DDR_EN_SHIFT) -#define QUADSPI_MCR_END_CFG_SHIFT 2 -#define QUADSPI_MCR_END_CFG_MASK (3 << QUADSPI_MCR_END_CFG_SHIFT) -#define QUADSPI_MCR_SWRSTHD_SHIFT 1 -#define QUADSPI_MCR_SWRSTHD_MASK (1 << QUADSPI_MCR_SWRSTHD_SHIFT) -#define QUADSPI_MCR_SWRSTSD_SHIFT 0 -#define QUADSPI_MCR_SWRSTSD_MASK (1 << QUADSPI_MCR_SWRSTSD_SHIFT) - -#define QUADSPI_IPCR 0x08 -#define QUADSPI_IPCR_SEQID_SHIFT 24 -#define QUADSPI_IPCR_SEQID_MASK (0xF << QUADSPI_IPCR_SEQID_SHIFT) - -#define QUADSPI_BUF0CR 0x10 -#define QUADSPI_BUF1CR 0x14 -#define QUADSPI_BUF2CR 0x18 -#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe - -#define QUADSPI_BUF3CR 0x1c -#define QUADSPI_BUF3CR_ALLMST_SHIFT 31 -#define QUADSPI_BUF3CR_ALLMST_MASK (1 << QUADSPI_BUF3CR_ALLMST_SHIFT) -#define QUADSPI_BUF3CR_ADATSZ_SHIFT 8 -#define QUADSPI_BUF3CR_ADATSZ_MASK (0xFF << QUADSPI_BUF3CR_ADATSZ_SHIFT) - -#define QUADSPI_BFGENCR 0x20 -#define QUADSPI_BFGENCR_PAR_EN_SHIFT 16 -#define QUADSPI_BFGENCR_PAR_EN_MASK (1 << (QUADSPI_BFGENCR_PAR_EN_SHIFT)) -#define QUADSPI_BFGENCR_SEQID_SHIFT 12 -#define QUADSPI_BFGENCR_SEQID_MASK (0xF << QUADSPI_BFGENCR_SEQID_SHIFT) - -#define QUADSPI_BUF0IND 0x30 -#define QUADSPI_BUF1IND 0x34 -#define QUADSPI_BUF2IND 0x38 -#define QUADSPI_SFAR 0x100 - -#define QUADSPI_SMPR 0x108 -#define QUADSPI_SMPR_DDRSMP_SHIFT 16 -#define QUADSPI_SMPR_DDRSMP_MASK (7 << QUADSPI_SMPR_DDRSMP_SHIFT) -#define QUADSPI_SMPR_FSDLY_SHIFT 6 -#define QUADSPI_SMPR_FSDLY_MASK (1 << QUADSPI_SMPR_FSDLY_SHIFT) -#define QUADSPI_SMPR_FSPHS_SHIFT 5 -#define QUADSPI_SMPR_FSPHS_MASK (1 << QUADSPI_SMPR_FSPHS_SHIFT) -#define QUADSPI_SMPR_HSENA_SHIFT 0 -#define QUADSPI_SMPR_HSENA_MASK (1 << QUADSPI_SMPR_HSENA_SHIFT) - -#define QUADSPI_RBSR 0x10c -#define QUADSPI_RBSR_RDBFL_SHIFT 8 -#define QUADSPI_RBSR_RDBFL_MASK (0x3F << QUADSPI_RBSR_RDBFL_SHIFT) - -#define QUADSPI_RBCT 0x110 -#define QUADSPI_RBCT_WMRK_MASK 0x1F -#define QUADSPI_RBCT_RXBRD_SHIFT 8 -#define QUADSPI_RBCT_RXBRD_USEIPS (0x1 << QUADSPI_RBCT_RXBRD_SHIFT) - -#define QUADSPI_TBSR 0x150 -#define QUADSPI_TBDR 0x154 -#define QUADSPI_SR 0x15c -#define QUADSPI_SR_IP_ACC_SHIFT 1 -#define QUADSPI_SR_IP_ACC_MASK (0x1 << QUADSPI_SR_IP_ACC_SHIFT) -#define QUADSPI_SR_AHB_ACC_SHIFT 2 -#define QUADSPI_SR_AHB_ACC_MASK (0x1 << QUADSPI_SR_AHB_ACC_SHIFT) - -#define QUADSPI_FR 0x160 -#define QUADSPI_FR_TFF_MASK 0x1 - -#define QUADSPI_SFA1AD 0x180 -#define QUADSPI_SFA2AD 0x184 -#define QUADSPI_SFB1AD 0x188 -#define QUADSPI_SFB2AD 0x18c -#define QUADSPI_RBDR 0x200 - -#define QUADSPI_LUTKEY 0x300 -#define QUADSPI_LUTKEY_VALUE 0x5AF05AF0 - -#define QUADSPI_LCKCR 0x304 -#define QUADSPI_LCKER_LOCK 0x1 -#define QUADSPI_LCKER_UNLOCK 0x2 - -#define QUADSPI_RSER 0x164 -#define QUADSPI_RSER_TFIE (0x1 << 0) - -#define QUADSPI_LUT_BASE 0x310 - -/* - * The definition of the LUT register shows below: - * - * --------------------------------------------------- - * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 | - * --------------------------------------------------- - */ -#define OPRND0_SHIFT 0 -#define PAD0_SHIFT 8 -#define INSTR0_SHIFT 10 -#define OPRND1_SHIFT 16 - -/* Instruction set for the LUT register. */ -#define LUT_STOP 0 -#define LUT_CMD 1 -#define LUT_ADDR 2 -#define LUT_DUMMY 3 -#define LUT_MODE 4 -#define LUT_MODE2 5 -#define LUT_MODE4 6 -#define LUT_FSL_READ 7 -#define LUT_FSL_WRITE 8 -#define LUT_JMP_ON_CS 9 -#define LUT_ADDR_DDR 10 -#define LUT_MODE_DDR 11 -#define LUT_MODE2_DDR 12 -#define LUT_MODE4_DDR 13 -#define LUT_FSL_READ_DDR 14 -#define LUT_FSL_WRITE_DDR 15 -#define LUT_DATA_LEARN 16 - -/* - * The PAD definitions for LUT register. - * - * The pad stands for the lines number of IO[0:3]. - * For example, the Quad read need four IO lines, so you should - * set LUT_PAD4 which means we use four IO lines. - */ -#define LUT_PAD1 0 -#define LUT_PAD2 1 -#define LUT_PAD4 2 - -/* Oprands for the LUT register. */ -#define ADDR24BIT 0x18 -#define ADDR32BIT 0x20 - -/* Macros for constructing the LUT register. */ -#define LUT0(ins, pad, opr) \ - (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \ - ((LUT_##ins) << INSTR0_SHIFT)) - -#define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT) - -/* other macros for LUT register. */ -#define QUADSPI_LUT(x) (QUADSPI_LUT_BASE + (x) * 4) -#define QUADSPI_LUT_NUM 64 - -/* SEQID -- we can have 16 seqids at most. */ -#define SEQID_READ 0 -#define SEQID_WREN 1 -#define SEQID_WRDI 2 -#define SEQID_RDSR 3 -#define SEQID_SE 4 -#define SEQID_CHIP_ERASE 5 -#define SEQID_PP 6 -#define SEQID_RDID 7 -#define SEQID_WRSR 8 -#define SEQID_RDCR 9 -#define SEQID_EN4B 10 -#define SEQID_BRWR 11 - -#define QUADSPI_MIN_IOMAP SZ_4M - -enum fsl_qspi_devtype { - FSL_QUADSPI_VYBRID, - FSL_QUADSPI_IMX6SX, - FSL_QUADSPI_IMX7D, - FSL_QUADSPI_IMX6UL, - FSL_QUADSPI_LS1021A, - FSL_QUADSPI_LS2080A, -}; - -struct fsl_qspi_devtype_data { - enum fsl_qspi_devtype devtype; - int rxfifo; - int txfifo; - int ahb_buf_size; - int driver_data; -}; - -static const struct fsl_qspi_devtype_data vybrid_data = { - .devtype = FSL_QUADSPI_VYBRID, - .rxfifo = 128, - .txfifo = 64, - .ahb_buf_size = 1024, - .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN, -}; - -static const struct fsl_qspi_devtype_data imx6sx_data = { - .devtype = FSL_QUADSPI_IMX6SX, - .rxfifo = 128, - .txfifo = 512, - .ahb_buf_size = 1024, - .driver_data = QUADSPI_QUIRK_4X_INT_CLK - | QUADSPI_QUIRK_TKT245618, -}; - -static const struct fsl_qspi_devtype_data imx7d_data = { - .devtype = FSL_QUADSPI_IMX7D, - .rxfifo = 512, - .txfifo = 512, - .ahb_buf_size = 1024, - .driver_data = QUADSPI_QUIRK_TKT253890 - | QUADSPI_QUIRK_4X_INT_CLK, -}; - -static const struct fsl_qspi_devtype_data imx6ul_data = { - .devtype = FSL_QUADSPI_IMX6UL, - .rxfifo = 128, - .txfifo = 512, - .ahb_buf_size = 1024, - .driver_data = QUADSPI_QUIRK_TKT253890 - | QUADSPI_QUIRK_4X_INT_CLK, -}; - -static struct fsl_qspi_devtype_data ls1021a_data = { - .devtype = FSL_QUADSPI_LS1021A, - .rxfifo = 128, - .txfifo = 64, - .ahb_buf_size = 1024, - .driver_data = 0, -}; - -static const struct fsl_qspi_devtype_data ls2080a_data = { - .devtype = FSL_QUADSPI_LS2080A, - .rxfifo = 128, - .txfifo = 64, - .ahb_buf_size = 1024, - .driver_data = QUADSPI_QUIRK_TKT253890, -}; - - -#define FSL_QSPI_MAX_CHIP 4 -struct fsl_qspi { - struct spi_nor nor[FSL_QSPI_MAX_CHIP]; - void __iomem *iobase; - void __iomem *ahb_addr; - u32 memmap_phy; - u32 memmap_offs; - u32 memmap_len; - struct clk *clk, *clk_en; - struct device *dev; - struct completion c; - const struct fsl_qspi_devtype_data *devtype_data; - u32 nor_size; - u32 nor_num; - u32 clk_rate; - unsigned int chip_base_addr; /* We may support two chips. */ - bool has_second_chip; - bool big_endian; - struct mutex lock; - struct pm_qos_request pm_qos_req; -}; - -static inline int needs_swap_endian(struct fsl_qspi *q) -{ - return q->devtype_data->driver_data & QUADSPI_QUIRK_SWAP_ENDIAN; -} - -static inline int needs_4x_clock(struct fsl_qspi *q) -{ - return q->devtype_data->driver_data & QUADSPI_QUIRK_4X_INT_CLK; -} - -static inline int needs_fill_txfifo(struct fsl_qspi *q) -{ - return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT253890; -} - -static inline int needs_wakeup_wait_mode(struct fsl_qspi *q) -{ - return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618; -} - -/* - * R/W functions for big- or little-endian registers: - * The qSPI controller's endian is independent of the CPU core's endian. - * So far, although the CPU core is little-endian but the qSPI have two - * versions for big-endian and little-endian. - */ -static void qspi_writel(struct fsl_qspi *q, u32 val, void __iomem *addr) -{ - if (q->big_endian) - iowrite32be(val, addr); - else - iowrite32(val, addr); -} - -static u32 qspi_readl(struct fsl_qspi *q, void __iomem *addr) -{ - if (q->big_endian) - return ioread32be(addr); - else - return ioread32(addr); -} - -/* - * An IC bug makes us to re-arrange the 32-bit data. - * The following chips, such as IMX6SLX, have fixed this bug. - */ -static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a) -{ - return needs_swap_endian(q) ? __swab32(a) : a; -} - -static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q) -{ - qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); - qspi_writel(q, QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR); -} - -static inline void fsl_qspi_lock_lut(struct fsl_qspi *q) -{ - qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); - qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR); -} - -static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id) -{ - struct fsl_qspi *q = dev_id; - u32 reg; - - /* clear interrupt */ - reg = qspi_readl(q, q->iobase + QUADSPI_FR); - qspi_writel(q, reg, q->iobase + QUADSPI_FR); - - if (reg & QUADSPI_FR_TFF_MASK) - complete(&q->c); - - dev_dbg(q->dev, "QUADSPI_FR : 0x%.8x:0x%.8x\n", q->chip_base_addr, reg); - return IRQ_HANDLED; -} - -static void fsl_qspi_init_lut(struct fsl_qspi *q) -{ - void __iomem *base = q->iobase; - int rxfifo = q->devtype_data->rxfifo; - u32 lut_base; - int i; - - struct spi_nor *nor = &q->nor[0]; - u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT; - u8 read_op = nor->read_opcode; - u8 read_dm = nor->read_dummy; - - fsl_qspi_unlock_lut(q); - - /* Clear all the LUT table */ - for (i = 0; i < QUADSPI_LUT_NUM; i++) - qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4); - - /* Read */ - lut_base = SEQID_READ * 4; - - qspi_writel(q, LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD1, addrlen), - base + QUADSPI_LUT(lut_base)); - qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | - LUT1(FSL_READ, PAD4, rxfifo), - base + QUADSPI_LUT(lut_base + 1)); - - /* Write enable */ - lut_base = SEQID_WREN * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN), - base + QUADSPI_LUT(lut_base)); - - /* Page Program */ - lut_base = SEQID_PP * 4; - - qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) | - LUT1(ADDR, PAD1, addrlen), - base + QUADSPI_LUT(lut_base)); - qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0), - base + QUADSPI_LUT(lut_base + 1)); - - /* Read Status */ - lut_base = SEQID_RDSR * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDSR) | - LUT1(FSL_READ, PAD1, 0x1), - base + QUADSPI_LUT(lut_base)); - - /* Erase a sector */ - lut_base = SEQID_SE * 4; - - qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) | - LUT1(ADDR, PAD1, addrlen), - base + QUADSPI_LUT(lut_base)); - - /* Erase the whole chip */ - lut_base = SEQID_CHIP_ERASE * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE), - base + QUADSPI_LUT(lut_base)); - - /* READ ID */ - lut_base = SEQID_RDID * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDID) | - LUT1(FSL_READ, PAD1, 0x8), - base + QUADSPI_LUT(lut_base)); - - /* Write Register */ - lut_base = SEQID_WRSR * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRSR) | - LUT1(FSL_WRITE, PAD1, 0x2), - base + QUADSPI_LUT(lut_base)); - - /* Read Configuration Register */ - lut_base = SEQID_RDCR * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDCR) | - LUT1(FSL_READ, PAD1, 0x1), - base + QUADSPI_LUT(lut_base)); - - /* Write disable */ - lut_base = SEQID_WRDI * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRDI), - base + QUADSPI_LUT(lut_base)); - - /* Enter 4 Byte Mode (Micron) */ - lut_base = SEQID_EN4B * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_EN4B), - base + QUADSPI_LUT(lut_base)); - - /* Enter 4 Byte Mode (Spansion) */ - lut_base = SEQID_BRWR * 4; - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR), - base + QUADSPI_LUT(lut_base)); - - fsl_qspi_lock_lut(q); -} - -/* Get the SEQID for the command */ -static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) -{ - switch (cmd) { - case SPINOR_OP_READ_1_1_4: - case SPINOR_OP_READ_1_1_4_4B: - return SEQID_READ; - case SPINOR_OP_WREN: - return SEQID_WREN; - case SPINOR_OP_WRDI: - return SEQID_WRDI; - case SPINOR_OP_RDSR: - return SEQID_RDSR; - case SPINOR_OP_SE: - return SEQID_SE; - case SPINOR_OP_CHIP_ERASE: - return SEQID_CHIP_ERASE; - case SPINOR_OP_PP: - return SEQID_PP; - case SPINOR_OP_RDID: - return SEQID_RDID; - case SPINOR_OP_WRSR: - return SEQID_WRSR; - case SPINOR_OP_RDCR: - return SEQID_RDCR; - case SPINOR_OP_EN4B: - return SEQID_EN4B; - case SPINOR_OP_BRWR: - return SEQID_BRWR; - default: - if (cmd == q->nor[0].erase_opcode) - return SEQID_SE; - dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd); - break; - } - return -EINVAL; -} - -static int -fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len) -{ - void __iomem *base = q->iobase; - int seqid; - u32 reg, reg2; - int err; - - init_completion(&q->c); - dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len:%d, cmd:%.2x\n", - q->chip_base_addr, addr, len, cmd); - - /* save the reg */ - reg = qspi_readl(q, base + QUADSPI_MCR); - - qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr, - base + QUADSPI_SFAR); - qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS, - base + QUADSPI_RBCT); - qspi_writel(q, reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR); - - do { - reg2 = qspi_readl(q, base + QUADSPI_SR); - if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) { - udelay(1); - dev_dbg(q->dev, "The controller is busy, 0x%x\n", reg2); - continue; - } - break; - } while (1); - - /* trigger the LUT now */ - seqid = fsl_qspi_get_seqid(q, cmd); - if (seqid < 0) - return seqid; - - qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, - base + QUADSPI_IPCR); - - /* Wait for the interrupt. */ - if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) { - dev_err(q->dev, - "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n", - cmd, addr, qspi_readl(q, base + QUADSPI_FR), - qspi_readl(q, base + QUADSPI_SR)); - err = -ETIMEDOUT; - } else { - err = 0; - } - - /* restore the MCR */ - qspi_writel(q, reg, base + QUADSPI_MCR); - - return err; -} - -/* Read out the data from the QUADSPI_RBDR buffer registers. */ -static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf) -{ - u32 tmp; - int i = 0; - - while (len > 0) { - tmp = qspi_readl(q, q->iobase + QUADSPI_RBDR + i * 4); - tmp = fsl_qspi_endian_xchg(q, tmp); - dev_dbg(q->dev, "chip addr:0x%.8x, rcv:0x%.8x\n", - q->chip_base_addr, tmp); - - if (len >= 4) { - *((u32 *)rxbuf) = tmp; - rxbuf += 4; - } else { - memcpy(rxbuf, &tmp, len); - break; - } - - len -= 4; - i++; - } -} - -/* - * If we have changed the content of the flash by writing or erasing, - * we need to invalidate the AHB buffer. If we do not do so, we may read out - * the wrong data. The spec tells us reset the AHB domain and Serial Flash - * domain at the same time. - */ -static inline void fsl_qspi_invalid(struct fsl_qspi *q) -{ - u32 reg; - - reg = qspi_readl(q, q->iobase + QUADSPI_MCR); - reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK; - qspi_writel(q, reg, q->iobase + QUADSPI_MCR); - - /* - * The minimum delay : 1 AHB + 2 SFCK clocks. - * Delay 1 us is enough. - */ - udelay(1); - - reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK); - qspi_writel(q, reg, q->iobase + QUADSPI_MCR); -} - -static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, - u8 opcode, unsigned int to, u32 *txbuf, - unsigned count) -{ - int ret, i, j; - u32 tmp; - - dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n", - q->chip_base_addr, to, count); - - /* clear the TX FIFO. */ - tmp = qspi_readl(q, q->iobase + QUADSPI_MCR); - qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR); - - /* fill the TX data to the FIFO */ - for (j = 0, i = ((count + 3) / 4); j < i; j++) { - tmp = fsl_qspi_endian_xchg(q, *txbuf); - qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR); - txbuf++; - } - - /* fill the TXFIFO upto 16 bytes for i.MX7d */ - if (needs_fill_txfifo(q)) - for (; i < 4; i++) - qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR); - - /* Trigger it */ - ret = fsl_qspi_runcmd(q, opcode, to, count); - - if (ret == 0) - return count; - - return ret; -} - -static void fsl_qspi_set_map_addr(struct fsl_qspi *q) -{ - int nor_size = q->nor_size; - void __iomem *base = q->iobase; - - qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD); - qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD); - qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD); - qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD); -} - -/* - * There are two different ways to read out the data from the flash: - * the "IP Command Read" and the "AHB Command Read". - * - * The IC guy suggests we use the "AHB Command Read" which is faster - * then the "IP Command Read". (What's more is that there is a bug in - * the "IP Command Read" in the Vybrid.) - * - * After we set up the registers for the "AHB Command Read", we can use - * the memcpy to read the data directly. A "missed" access to the buffer - * causes the controller to clear the buffer, and use the sequence pointed - * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash. - */ -static int fsl_qspi_init_ahb_read(struct fsl_qspi *q) -{ - void __iomem *base = q->iobase; - int seqid; - - /* AHB configuration for access buffer 0/1/2 .*/ - qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR); - qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR); - qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR); - /* - * Set ADATSZ with the maximum AHB buffer size to improve the - * read performance. - */ - qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK | - ((q->devtype_data->ahb_buf_size / 8) - << QUADSPI_BUF3CR_ADATSZ_SHIFT), - base + QUADSPI_BUF3CR); - - /* We only use the buffer3 */ - qspi_writel(q, 0, base + QUADSPI_BUF0IND); - qspi_writel(q, 0, base + QUADSPI_BUF1IND); - qspi_writel(q, 0, base + QUADSPI_BUF2IND); - - /* Set the default lut sequence for AHB Read. */ - seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode); - if (seqid < 0) - return seqid; - - qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT, - q->iobase + QUADSPI_BFGENCR); - - return 0; -} - -/* This function was used to prepare and enable QSPI clock */ -static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q) -{ - int ret; - - ret = clk_prepare_enable(q->clk_en); - if (ret) - return ret; - - ret = clk_prepare_enable(q->clk); - if (ret) { - clk_disable_unprepare(q->clk_en); - return ret; - } - - if (needs_wakeup_wait_mode(q)) - pm_qos_add_request(&q->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0); - - return 0; -} - -/* This function was used to disable and unprepare QSPI clock */ -static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q) -{ - if (needs_wakeup_wait_mode(q)) - pm_qos_remove_request(&q->pm_qos_req); - - clk_disable_unprepare(q->clk); - clk_disable_unprepare(q->clk_en); - -} - -/* We use this function to do some basic init for spi_nor_scan(). */ -static int fsl_qspi_nor_setup(struct fsl_qspi *q) -{ - void __iomem *base = q->iobase; - u32 reg; - int ret; - - /* disable and unprepare clock to avoid glitch pass to controller */ - fsl_qspi_clk_disable_unprep(q); - - /* the default frequency, we will change it in the future. */ - ret = clk_set_rate(q->clk, 66000000); - if (ret) - return ret; - - ret = fsl_qspi_clk_prep_enable(q); - if (ret) - return ret; - - /* Reset the module */ - qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK, - base + QUADSPI_MCR); - udelay(1); - - /* Init the LUT table. */ - fsl_qspi_init_lut(q); - - /* Disable the module */ - qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK, - base + QUADSPI_MCR); - - reg = qspi_readl(q, base + QUADSPI_SMPR); - qspi_writel(q, reg & ~(QUADSPI_SMPR_FSDLY_MASK - | QUADSPI_SMPR_FSPHS_MASK - | QUADSPI_SMPR_HSENA_MASK - | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR); - - /* Enable the module */ - qspi_writel(q, QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK, - base + QUADSPI_MCR); - - /* clear all interrupt status */ - qspi_writel(q, 0xffffffff, q->iobase + QUADSPI_FR); - - /* enable the interrupt */ - qspi_writel(q, QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER); - - return 0; -} - -static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) -{ - unsigned long rate = q->clk_rate; - int ret; - - if (needs_4x_clock(q)) - rate *= 4; - - /* disable and unprepare clock to avoid glitch pass to controller */ - fsl_qspi_clk_disable_unprep(q); - - ret = clk_set_rate(q->clk, rate); - if (ret) - return ret; - - ret = fsl_qspi_clk_prep_enable(q); - if (ret) - return ret; - - /* Init the LUT table again. */ - fsl_qspi_init_lut(q); - - /* Init for AHB read */ - return fsl_qspi_init_ahb_read(q); -} - -static const struct of_device_id fsl_qspi_dt_ids[] = { - { .compatible = "fsl,vf610-qspi", .data = &vybrid_data, }, - { .compatible = "fsl,imx6sx-qspi", .data = &imx6sx_data, }, - { .compatible = "fsl,imx7d-qspi", .data = &imx7d_data, }, - { .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, }, - { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, }, - { .compatible = "fsl,ls2080a-qspi", .data = &ls2080a_data, }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); - -static void fsl_qspi_set_base_addr(struct fsl_qspi *q, struct spi_nor *nor) -{ - q->chip_base_addr = q->nor_size * (nor - q->nor); -} - -static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) -{ - int ret; - struct fsl_qspi *q = nor->priv; - - ret = fsl_qspi_runcmd(q, opcode, 0, len); - if (ret) - return ret; - - fsl_qspi_read_data(q, len, buf); - return 0; -} - -static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) -{ - struct fsl_qspi *q = nor->priv; - int ret; - - if (!buf) { - ret = fsl_qspi_runcmd(q, opcode, 0, 1); - if (ret) - return ret; - - if (opcode == SPINOR_OP_CHIP_ERASE) - fsl_qspi_invalid(q); - - } else if (len > 0) { - ret = fsl_qspi_nor_write(q, nor, opcode, 0, - (u32 *)buf, len); - if (ret > 0) - return 0; - } else { - dev_err(q->dev, "invalid cmd %d\n", opcode); - ret = -EINVAL; - } - - return ret; -} - -static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to, - size_t len, const u_char *buf) -{ - struct fsl_qspi *q = nor->priv; - ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to, - (u32 *)buf, len); - - /* invalid the data in the AHB buffer. */ - fsl_qspi_invalid(q); - return ret; -} - -static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from, - size_t len, u_char *buf) -{ - struct fsl_qspi *q = nor->priv; - u8 cmd = nor->read_opcode; - - /* if necessary,ioremap buffer before AHB read, */ - if (!q->ahb_addr) { - q->memmap_offs = q->chip_base_addr + from; - q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP; - - q->ahb_addr = ioremap_nocache( - q->memmap_phy + q->memmap_offs, - q->memmap_len); - if (!q->ahb_addr) { - dev_err(q->dev, "ioremap failed\n"); - return -ENOMEM; - } - /* ioremap if the data requested is out of range */ - } else if (q->chip_base_addr + from < q->memmap_offs - || q->chip_base_addr + from + len > - q->memmap_offs + q->memmap_len) { - iounmap(q->ahb_addr); - - q->memmap_offs = q->chip_base_addr + from; - q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP; - q->ahb_addr = ioremap_nocache( - q->memmap_phy + q->memmap_offs, - q->memmap_len); - if (!q->ahb_addr) { - dev_err(q->dev, "ioremap failed\n"); - return -ENOMEM; - } - } - - dev_dbg(q->dev, "cmd [%x],read from %p, len:%zd\n", - cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, - len); - - /* Read out the data directly from the AHB buffer.*/ - memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, - len); - - return len; -} - -static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) -{ - struct fsl_qspi *q = nor->priv; - int ret; - - dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n", - nor->mtd.erasesize / 1024, q->chip_base_addr, (u32)offs); - - ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0); - if (ret) - return ret; - - fsl_qspi_invalid(q); - return 0; -} - -static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) -{ - struct fsl_qspi *q = nor->priv; - int ret; - - mutex_lock(&q->lock); - - ret = fsl_qspi_clk_prep_enable(q); - if (ret) - goto err_mutex; - - fsl_qspi_set_base_addr(q, nor); - return 0; - -err_mutex: - mutex_unlock(&q->lock); - return ret; -} - -static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) -{ - struct fsl_qspi *q = nor->priv; - - fsl_qspi_clk_disable_unprep(q); - mutex_unlock(&q->lock); -} - -static int fsl_qspi_probe(struct platform_device *pdev) -{ - const struct spi_nor_hwcaps hwcaps = { - .mask = SNOR_HWCAPS_READ_1_1_4 | - SNOR_HWCAPS_PP, - }; - struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - struct fsl_qspi *q; - struct resource *res; - struct spi_nor *nor; - struct mtd_info *mtd; - int ret, i = 0; - - q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL); - if (!q) - return -ENOMEM; - - q->nor_num = of_get_child_count(dev->of_node); - if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP) - return -ENODEV; - - q->dev = dev; - q->devtype_data = of_device_get_match_data(dev); - if (!q->devtype_data) - return -ENODEV; - platform_set_drvdata(pdev, q); - - /* find the resources */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI"); - q->iobase = devm_ioremap_resource(dev, res); - if (IS_ERR(q->iobase)) - return PTR_ERR(q->iobase); - - q->big_endian = of_property_read_bool(np, "big-endian"); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "QuadSPI-memory"); - if (!devm_request_mem_region(dev, res->start, resource_size(res), - res->name)) { - dev_err(dev, "can't request region for resource %pR\n", res); - return -EBUSY; - } - - q->memmap_phy = res->start; - - /* find the clocks */ - q->clk_en = devm_clk_get(dev, "qspi_en"); - if (IS_ERR(q->clk_en)) - return PTR_ERR(q->clk_en); - - q->clk = devm_clk_get(dev, "qspi"); - if (IS_ERR(q->clk)) - return PTR_ERR(q->clk); - - ret = fsl_qspi_clk_prep_enable(q); - if (ret) { - dev_err(dev, "can not enable the clock\n"); - goto clk_failed; - } - - /* find the irq */ - ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "failed to get the irq: %d\n", ret); - goto irq_failed; - } - - ret = devm_request_irq(dev, ret, - fsl_qspi_irq_handler, 0, pdev->name, q); - if (ret) { - dev_err(dev, "failed to request irq: %d\n", ret); - goto irq_failed; - } - - ret = fsl_qspi_nor_setup(q); - if (ret) - goto irq_failed; - - if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) - q->has_second_chip = true; - - mutex_init(&q->lock); - - /* iterate the subnodes. */ - for_each_available_child_of_node(dev->of_node, np) { - /* skip the holes */ - if (!q->has_second_chip) - i *= 2; - - nor = &q->nor[i]; - mtd = &nor->mtd; - - nor->dev = dev; - spi_nor_set_flash_node(nor, np); - nor->priv = q; - - if (q->nor_num > 1 && !mtd->name) { - int spiflash_idx; - - ret = of_property_read_u32(np, "reg", &spiflash_idx); - if (!ret) { - mtd->name = devm_kasprintf(dev, GFP_KERNEL, - "%s-%d", - dev_name(dev), - spiflash_idx); - if (!mtd->name) { - ret = -ENOMEM; - goto mutex_failed; - } - } else { - dev_warn(dev, "reg property is missing\n"); - } - } - - /* fill the hooks */ - nor->read_reg = fsl_qspi_read_reg; - nor->write_reg = fsl_qspi_write_reg; - nor->read = fsl_qspi_read; - nor->write = fsl_qspi_write; - nor->erase = fsl_qspi_erase; - - nor->prepare = fsl_qspi_prep; - nor->unprepare = fsl_qspi_unprep; - - ret = of_property_read_u32(np, "spi-max-frequency", - &q->clk_rate); - if (ret < 0) - goto mutex_failed; - - /* set the chip address for READID */ - fsl_qspi_set_base_addr(q, nor); - - ret = spi_nor_scan(nor, NULL, &hwcaps); - if (ret) - goto mutex_failed; - - ret = mtd_device_register(mtd, NULL, 0); - if (ret) - goto mutex_failed; - - /* Set the correct NOR size now. */ - if (q->nor_size == 0) { - q->nor_size = mtd->size; - - /* Map the SPI NOR to accessiable address */ - fsl_qspi_set_map_addr(q); - } - - /* - * The TX FIFO is 64 bytes in the Vybrid, but the Page Program - * may writes 265 bytes per time. The write is working in the - * unit of the TX FIFO, not in the unit of the SPI NOR's page - * size. - * - * So shrink the spi_nor->page_size if it is larger then the - * TX FIFO. - */ - if (nor->page_size > q->devtype_data->txfifo) - nor->page_size = q->devtype_data->txfifo; - - i++; - } - - /* finish the rest init. */ - ret = fsl_qspi_nor_setup_last(q); - if (ret) - goto last_init_failed; - - fsl_qspi_clk_disable_unprep(q); - return 0; - -last_init_failed: - for (i = 0; i < q->nor_num; i++) { - /* skip the holes */ - if (!q->has_second_chip) - i *= 2; - mtd_device_unregister(&q->nor[i].mtd); - } -mutex_failed: - mutex_destroy(&q->lock); -irq_failed: - fsl_qspi_clk_disable_unprep(q); -clk_failed: - dev_err(dev, "Freescale QuadSPI probe failed\n"); - return ret; -} - -static int fsl_qspi_remove(struct platform_device *pdev) -{ - struct fsl_qspi *q = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < q->nor_num; i++) { - /* skip the holes */ - if (!q->has_second_chip) - i *= 2; - mtd_device_unregister(&q->nor[i].mtd); - } - - /* disable the hardware */ - qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); - qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER); - - mutex_destroy(&q->lock); - - if (q->ahb_addr) - iounmap(q->ahb_addr); - - return 0; -} - -static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state) -{ - return 0; -} - -static int fsl_qspi_resume(struct platform_device *pdev) -{ - int ret; - struct fsl_qspi *q = platform_get_drvdata(pdev); - - ret = fsl_qspi_clk_prep_enable(q); - if (ret) - return ret; - - fsl_qspi_nor_setup(q); - fsl_qspi_set_map_addr(q); - fsl_qspi_nor_setup_last(q); - - fsl_qspi_clk_disable_unprep(q); - - return 0; -} - -static struct platform_driver fsl_qspi_driver = { - .driver = { - .name = "fsl-quadspi", - .of_match_table = fsl_qspi_dt_ids, - }, - .probe = fsl_qspi_probe, - .remove = fsl_qspi_remove, - .suspend = fsl_qspi_suspend, - .resume = fsl_qspi_resume, -}; -module_platform_driver(fsl_qspi_driver); - -MODULE_DESCRIPTION("Freescale QuadSPI Controller Driver"); -MODULE_AUTHOR("Freescale Semiconductor Inc."); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 557ce9d755d5ffc735f03a9a2ce2f1b4a3b23bd6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 4 Jan 2019 22:42:36 +0800 Subject: regulator: act8945a: Use rdev_get_id() to access id of regulator Use rdev_get_id() instead of directly access rdev->desc->id. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/act8945a-regulator.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/act8945a-regulator.c b/drivers/regulator/act8945a-regulator.c index 603db77723b6..caa61d306a69 100644 --- a/drivers/regulator/act8945a-regulator.c +++ b/drivers/regulator/act8945a-regulator.c @@ -87,7 +87,8 @@ static const struct regulator_linear_range act8945a_voltage_ranges[] = { static int act8945a_set_suspend_state(struct regulator_dev *rdev, bool enable) { struct regmap *regmap = rdev->regmap; - int id = rdev->desc->id, reg, val; + int id = rdev_get_id(rdev); + int reg, val; switch (id) { case ACT8945A_ID_DCDC1: @@ -159,7 +160,7 @@ static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev); struct regmap *regmap = rdev->regmap; - int id = rdev->desc->id; + int id = rdev_get_id(rdev); int reg, ret, val = 0; switch (id) { @@ -190,11 +191,11 @@ static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode) switch (mode) { case REGULATOR_MODE_STANDBY: - if (rdev->desc->id > ACT8945A_ID_DCDC3) + if (id > ACT8945A_ID_DCDC3) val = BIT(5); break; case REGULATOR_MODE_NORMAL: - if (rdev->desc->id <= ACT8945A_ID_DCDC3) + if (id <= ACT8945A_ID_DCDC3) val = BIT(5); break; default: @@ -213,7 +214,7 @@ static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode) static unsigned int act8945a_get_mode(struct regulator_dev *rdev) { struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev); - int id = rdev->desc->id; + int id = rdev_get_id(rdev); if (id < ACT8945A_ID_DCDC1 || id >= ACT8945A_ID_MAX) return -EINVAL; -- cgit v1.2.3 From 5f5b4fa522e630cfa154c59ae7649b5568913f96 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 7 Jan 2019 13:08:30 -0500 Subject: ipu3: add missing #include Lots of warning due to non-static functions are generated because the headers with define them were not included. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/ipu3-css-params.c | 1 + drivers/staging/media/ipu3/ipu3-dmamap.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/media/ipu3/ipu3-css-params.c b/drivers/staging/media/ipu3/ipu3-css-params.c index 776206ded83b..053edce54b71 100644 --- a/drivers/staging/media/ipu3/ipu3-css-params.c +++ b/drivers/staging/media/ipu3/ipu3-css-params.c @@ -6,6 +6,7 @@ #include "ipu3-css.h" #include "ipu3-css-fw.h" #include "ipu3-tables.h" +#include "ipu3-css-params.h" #define DIV_ROUND_CLOSEST_DOWN(a, b) (((a) + ((b) / 2) - 1) / (b)) #define roundclosest_down(a, b) (DIV_ROUND_CLOSEST_DOWN(a, b) * (b)) diff --git a/drivers/staging/media/ipu3/ipu3-dmamap.c b/drivers/staging/media/ipu3/ipu3-dmamap.c index 93a393d4e15e..5bed01d5b8df 100644 --- a/drivers/staging/media/ipu3/ipu3-dmamap.c +++ b/drivers/staging/media/ipu3/ipu3-dmamap.c @@ -12,6 +12,7 @@ #include "ipu3.h" #include "ipu3-css-pool.h" #include "ipu3-mmu.h" +#include "ipu3-dmamap.h" /* * Free a buffer allocated by ipu3_dmamap_alloc_buffer() -- cgit v1.2.3 From aa54c1c9d90e6db75190813907190fadcce1bf45 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 26 Dec 2018 22:45:06 +0100 Subject: spi: fix initial SPI_SR value in spi-fsl-dspi On ColdFire mcf54418, using DSPI_DMA_MODE mode, spi transfers at first boot stage are not succeding: m25p80 spi0.1: unrecognized JEDEC id bytes: 00, 00, 00 The reason is the SPI_SR initial value set by the driver, that is not clearing (not setting to 1) the RF_DF flag. After a tour on the dspi hw modules that use this driver(Vybrid, ColdFire and ls1021a) a better init value for SR register has been set. Signed-off-by: Angelo Dureghello Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 5e10dc5c93a5..7b605f95dbef 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -67,7 +67,7 @@ #define SPI_SR 0x2c #define SPI_SR_EOQF 0x10000000 #define SPI_SR_TCFQF 0x80000000 -#define SPI_SR_CLEAR 0xdaad0000 +#define SPI_SR_CLEAR 0x9aaf0000 #define SPI_RSER_TFFFE BIT(25) #define SPI_RSER_TFFFD BIT(24) -- cgit v1.2.3 From e2d8ffe2e76028457759988ba6216fd13eeea01b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 13 Nov 2018 03:52:18 -0500 Subject: media: v4l2-mem2mem: add v4l2_m2m_buf_copy_data helper function Memory-to-memory devices should copy various parts of struct v4l2_buffer from the output buffer to the capture buffer. Add a helper function that does that to simplify the driver code. Signed-off-by: Hans Verkuil Reviewed-by: Paul Kocialkowski Reviewed-by: Alexandre Courbot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mem2mem.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 5bbdec55b7d7..631f4e2aa942 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -975,6 +975,26 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, } EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue); +void v4l2_m2m_buf_copy_data(const struct vb2_v4l2_buffer *out_vb, + struct vb2_v4l2_buffer *cap_vb, + bool copy_frame_flags) +{ + u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + + if (copy_frame_flags) + mask |= V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_BFRAME; + + cap_vb->vb2_buf.timestamp = out_vb->vb2_buf.timestamp; + + if (out_vb->flags & V4L2_BUF_FLAG_TIMECODE) + cap_vb->timecode = out_vb->timecode; + cap_vb->field = out_vb->field; + cap_vb->flags &= ~mask; + cap_vb->flags |= out_vb->flags & mask; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_buf_copy_data); + void v4l2_m2m_request_queue(struct media_request *req) { struct media_request_object *obj, *obj_safe; -- cgit v1.2.3 From 0dcdcd0e42d33cd5e592935aa7a93e5461c1ddb9 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 26 Dec 2018 22:43:00 +0100 Subject: spi: add cpu details to fsl-dspi Kconfig help Add some cpu families that are actually using the fsl-dspi module in the related Kconfig description. Signed-off-by: Angelo Dureghello Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e22fc233ed07..ba68fe1913cb 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -383,7 +383,7 @@ config SPI_FSL_DSPI depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || M5441x || COMPILE_TEST help This enables support for the Freescale DSPI controller in master - mode. VF610 platform uses the controller. + mode. VF610, LS1021A and ColdFire platforms uses the controller. config SPI_FSL_ESPI tristate "Freescale eSPI controller" -- cgit v1.2.3 From e1bc204894eae69b153eb63d9fd65414466fb639 Mon Sep 17 00:00:00 2001 From: shaftarger Date: Fri, 28 Dec 2018 16:33:12 +0800 Subject: spi: dw: fix potential variable assignment error spi::mode is defined by framework for several SPI capabilities, such as polarity, phase, bit-endian, wire number. Directly use this variable for setting controller's polarity and phase causes other bit in register being set. Since SPI framework has its definition, SPI_CPOL and SPI_CPHA offset may be changed by framwork change. Instead of just mask off the relevant bits, fetch required bit in spi::mode and set to register. Signed-off-by: shaftarger Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 2e822a56576a..a945fad3db62 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -317,7 +317,8 @@ static int dw_spi_transfer_one(struct spi_controller *master, /* Default SPI mode is SCPOL = 0, SCPH = 0 */ cr0 = (transfer->bits_per_word - 1) | (chip->type << SPI_FRF_OFFSET) - | (spi->mode << SPI_MODE_OFFSET) + | ((((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET) | + (((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET)) | (chip->tmode << SPI_TMOD_OFFSET); /* -- cgit v1.2.3 From 7aca565ee3d0febeb980545a5ce72452b401ac90 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 24 Oct 2018 06:51:20 -0400 Subject: media: vim2m: use v4l2_m2m_buf_copy_data Use the new v4l2_m2m_buf_copy_data() function in vim2m. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vim2m.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index d01821a6906a..33397d4a1402 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -241,17 +241,7 @@ static int device_process(struct vim2m_ctx *ctx, out_vb->sequence = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++; in_vb->sequence = q_data->sequence++; - out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp; - - if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE) - out_vb->timecode = in_vb->timecode; - out_vb->field = in_vb->field; - out_vb->flags = in_vb->flags & - (V4L2_BUF_FLAG_TIMECODE | - V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME | - V4L2_BUF_FLAG_TSTAMP_SRC_MASK); + v4l2_m2m_buf_copy_data(out_vb, in_vb, true); switch (ctx->mode) { case MEM2MEM_HFLIP | MEM2MEM_VFLIP: -- cgit v1.2.3 From 96bddd5ff590e11b47255cf06af5a0d5ccaa7807 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 24 Oct 2018 06:51:30 -0400 Subject: media: vicodec: use v4l2_m2m_buf_copy_data Use the new v4l2_m2m_buf_copy_data() function in vicodec. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 0d7876f5acf0..2378582d9790 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -190,18 +190,8 @@ static int device_process(struct vicodec_ctx *ctx, } dst_vb->sequence = q_dst->sequence++; - dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; - - if (src_vb->flags & V4L2_BUF_FLAG_TIMECODE) - dst_vb->timecode = src_vb->timecode; - dst_vb->field = src_vb->field; dst_vb->flags &= ~V4L2_BUF_FLAG_LAST; - dst_vb->flags |= src_vb->flags & - (V4L2_BUF_FLAG_TIMECODE | - V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME | - V4L2_BUF_FLAG_TSTAMP_SRC_MASK); + v4l2_m2m_buf_copy_data(src_vb, dst_vb, !ctx->is_enc); return 0; } -- cgit v1.2.3 From 245ede423b43a6e081e94e0e5d4e895bd1f31228 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 24 Oct 2018 06:51:01 -0400 Subject: media: vb2: add vb2_find_timestamp() Use v4l2_timeval_to_ns instead of timeval_to_ns to ensure that both kernelspace and userspace will use the same conversion function. Next add a new vb2_find_timestamp() function to find buffers with a specific timestamp. This function will only look at DEQUEUED and DONE buffers, i.e. buffers that are already processed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-v4l2.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 3a0ca2f9854f..75ea90e795d8 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -143,7 +143,7 @@ static void __copy_timestamp(struct vb2_buffer *vb, const void *pb) * and the timecode field and flag if needed. */ if (q->copy_timestamp) - vb->timestamp = timeval_to_ns(&b->timestamp); + vb->timestamp = v4l2_timeval_to_ns(&b->timestamp); vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; if (b->flags & V4L2_BUF_FLAG_TIMECODE) vbuf->timecode = b->timecode; @@ -589,6 +589,23 @@ static const struct vb2_buf_ops v4l2_buf_ops = { .copy_timestamp = __copy_timestamp, }; +int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp, + unsigned int start_idx) +{ + unsigned int i; + + for (i = start_idx; i < q->num_buffers; i++) { + struct vb2_buffer *vb = q->bufs[i]; + + if ((vb->state == VB2_BUF_STATE_DEQUEUED || + vb->state == VB2_BUF_STATE_DONE) && + vb->timestamp == timestamp) + return i; + } + return -1; +} +EXPORT_SYMBOL_GPL(vb2_find_timestamp); + /* * vb2_querybuf() - query video buffer information * @q: videobuf queue -- cgit v1.2.3 From d998e03e322fc497454f584adfc35743713a44c5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 9 Nov 2018 04:16:21 -0500 Subject: media: cedrus: identify buffers by timestamp Use the new v4l2_m2m_buf_copy_data helper function and use timestamps to refer to reference frames instead of using buffer indices. Also remove the padding fields in the structs, that's a bad idea. Just use the right types to keep everything aligned. Signed-off-by: Hans Verkuil Tested-by: Paul Kocialkowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 9 --------- drivers/staging/media/sunxi/cedrus/cedrus.h | 9 ++++++--- drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 2 ++ drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c | 23 +++++++++++------------ 4 files changed, 19 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 5e3806feb5d7..e3bd441fa29a 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1661,15 +1661,6 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, return -EINVAL; } - if (p_mpeg2_slice_params->backward_ref_index >= VIDEO_MAX_FRAME || - p_mpeg2_slice_params->forward_ref_index >= VIDEO_MAX_FRAME) - return -EINVAL; - - if (p_mpeg2_slice_params->pad || - p_mpeg2_slice_params->picture.pad || - p_mpeg2_slice_params->sequence.pad) - return -EINVAL; - return 0; case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 3acfdcf83691..4aedd24a9848 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -140,11 +140,14 @@ static inline dma_addr_t cedrus_buf_addr(struct vb2_buffer *buf, } static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx, - unsigned int index, - unsigned int plane) + int index, unsigned int plane) { - struct vb2_buffer *buf = ctx->dst_bufs[index]; + struct vb2_buffer *buf; + if (index < 0) + return 0; + + buf = ctx->dst_bufs[index]; return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 591d191d4286..443fb037e1cf 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -50,6 +50,8 @@ void cedrus_device_run(void *priv) break; } + v4l2_m2m_buf_copy_data(run.src, run.dst, true); + dev->dec_ops[ctx->current_codec]->setup(ctx, &run); /* Complete request(s) controls if needed. */ diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index 9abd39cae38c..cb45fda9aaeb 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -82,7 +82,10 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) dma_addr_t fwd_luma_addr, fwd_chroma_addr; dma_addr_t bwd_luma_addr, bwd_chroma_addr; struct cedrus_dev *dev = ctx->dev; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; const u8 *matrix; + int forward_idx; + int backward_idx; unsigned int i; u32 reg; @@ -156,23 +159,19 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) cedrus_write(dev, VE_DEC_MPEG_PICBOUNDSIZE, reg); /* Forward and backward prediction reference buffers. */ + forward_idx = vb2_find_timestamp(cap_q, + slice_params->forward_ref_ts, 0); - fwd_luma_addr = cedrus_dst_buf_addr(ctx, - slice_params->forward_ref_index, - 0); - fwd_chroma_addr = cedrus_dst_buf_addr(ctx, - slice_params->forward_ref_index, - 1); + fwd_luma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 0); + fwd_chroma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 1); cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr); cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr); - bwd_luma_addr = cedrus_dst_buf_addr(ctx, - slice_params->backward_ref_index, - 0); - bwd_chroma_addr = cedrus_dst_buf_addr(ctx, - slice_params->backward_ref_index, - 1); + backward_idx = vb2_find_timestamp(cap_q, + slice_params->backward_ref_ts, 0); + bwd_luma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 0); + bwd_chroma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 1); cedrus_write(dev, VE_DEC_MPEG_BWD_REF_LUMA_ADDR, bwd_luma_addr); cedrus_write(dev, VE_DEC_MPEG_BWD_REF_CHROMA_ADDR, bwd_chroma_addr); -- cgit v1.2.3 From d57a984ff7aa1f8aac617c5ccfcd4cca061d2eb3 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:27 +0100 Subject: spi: stm32: switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index ad1e55d3d5d5..5f30578a4224 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1,23 +1,10 @@ -/* - * STMicroelectronics STM32 SPI Controller driver (master mode only) - * - * Copyright (C) 2017, STMicroelectronics - All Rights Reserved - * Author(s): Amelie Delaunay for STMicroelectronics. - * - * License terms: GPL V2.0. - * - * spi_stm32 driver is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * spi_stm32 driver is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * spi_stm32 driver. If not, see . - */ +// SPDX-License-Identifier: GPL-2.0 +// +// STMicroelectronics STM32 SPI Controller driver (master mode only) +// +// Copyright (C) 2017, STMicroelectronics - All Rights Reserved +// Author(s): Amelie Delaunay for STMicroelectronics. + #include #include #include -- cgit v1.2.3 From d4c9134a6c2c85d18b0d58accdf0e9be447f77a3 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:28 +0100 Subject: spi: stm32: use NULL pointer instead of plain integer Patch fixes sparse warning: Using plain integer as NULL pointer. Replaces second argument of function devm_clk_get from 0 to NULL. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 5f30578a4224..51d7f720127b 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1100,7 +1100,7 @@ static int stm32_spi_probe(struct platform_device *pdev) goto err_master_put; } - spi->clk = devm_clk_get(&pdev->dev, 0); + spi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(spi->clk)) { ret = PTR_ERR(spi->clk); dev_err(&pdev->dev, "clk get failed: %d\n", ret); -- cgit v1.2.3 From 2cbee7f886b2ab6b723745b295379ec6475f2ee3 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:29 +0100 Subject: spi: stm32: fix DMA configuration with only one channel When SPI driver is configured to work only with TX or RX DMA channel then dmaengine functions can dereferene NULL pointer. Running full-duplex mode when when only RX or TX DMA channel is available can cause overrun condition or incorrect writing to transmit buffer so disable this types of DMA configuration and go back to interrupt mode. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 51d7f720127b..8310f14fe273 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -427,9 +427,9 @@ static void stm32_spi_disable(struct stm32_spi *spi) if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) stm32_spi_read_rxfifo(spi, true); - if (spi->cur_usedma && spi->tx_buf) + if (spi->cur_usedma && spi->dma_tx) dmaengine_terminate_all(spi->dma_tx); - if (spi->cur_usedma && spi->rx_buf) + if (spi->cur_usedma && spi->dma_rx) dmaengine_terminate_all(spi->dma_rx); stm32_spi_clr_bits(spi, STM32_SPI_CR1, SPI_CR1_SPE); @@ -750,7 +750,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, spin_lock_irqsave(&spi->lock, flags); rx_dma_desc = NULL; - if (spi->rx_buf) { + if (spi->rx_buf && spi->dma_rx) { stm32_spi_dma_config(spi, &rx_dma_conf, DMA_DEV_TO_MEM); dmaengine_slave_config(spi->dma_rx, &rx_dma_conf); @@ -765,7 +765,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, } tx_dma_desc = NULL; - if (spi->tx_buf) { + if (spi->tx_buf && spi->dma_tx) { stm32_spi_dma_config(spi, &tx_dma_conf, DMA_MEM_TO_DEV); dmaengine_slave_config(spi->dma_tx, &tx_dma_conf); @@ -776,8 +776,11 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, DMA_PREP_INTERRUPT); } - if ((spi->tx_buf && !tx_dma_desc) || - (spi->rx_buf && !rx_dma_desc)) + if ((spi->tx_buf && spi->dma_tx && !tx_dma_desc) || + (spi->rx_buf && spi->dma_rx && !rx_dma_desc)) + goto dma_desc_error; + + if (spi->cur_comm == SPI_FULL_DUPLEX && (!tx_dma_desc || !rx_dma_desc)) goto dma_desc_error; if (rx_dma_desc) { @@ -822,7 +825,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, return 1; dma_submit_error: - if (spi->rx_buf) + if (spi->dma_rx) dmaengine_terminate_all(spi->dma_rx); dma_desc_error: @@ -832,6 +835,7 @@ dma_desc_error: dev_info(spi->dev, "DMA issue: fall back to irq transfer\n"); + spi->cur_usedma = false; return stm32_spi_transfer_one_irq(spi); } @@ -984,7 +988,7 @@ static int stm32_spi_transfer_one(struct spi_master *master, spi->rx_len = spi->rx_buf ? transfer->len : 0; spi->cur_usedma = (master->can_dma && - stm32_spi_can_dma(master, spi_dev, transfer)); + master->can_dma(master, spi_dev, transfer)); ret = stm32_spi_transfer_one_setup(spi, spi_dev, transfer); if (ret) { -- cgit v1.2.3 From bb35c9f91a8dec397e76f332dd93637e396e9054 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:30 +0100 Subject: spi: fix typo in SPI_STM32 help text Fix typo from STMicroelectonics to STMicroelectronics. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba68fe1913cb..dc67eda1788a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -676,7 +676,7 @@ config SPI_STM32 tristate "STMicroelectronics STM32 SPI controller" depends on ARCH_STM32 || COMPILE_TEST help - SPI driver for STMicroelectonics STM32 SoCs. + SPI driver for STMicroelectronics STM32 SoCs. STM32 SPI controller supports DMA and PIO modes. When DMA is not available, the driver automatically falls back to -- cgit v1.2.3 From d6cea11b092a2c28ecf8371c093214cbb112e926 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:31 +0100 Subject: spi: stm32: use explicit CPOL and CPHA mode bits Driver supports SPI mode 0 to 3 not only the mode 3. Use SPI_CPOL and SPI_CPHA indicates that these bits can be changed to obtain modes 0 - 3. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 8310f14fe273..f7056b767477 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1142,7 +1142,7 @@ static int stm32_spi_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; master->bus_num = pdev->id; - master->mode_bits = SPI_MODE_3 | SPI_CS_HIGH | SPI_LSB_FIRST | + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP; master->bits_per_word_mask = stm32_spi_get_bpw_mask(spi); master->max_speed_hz = spi->clk_rate / SPI_MBR_DIV_MIN; -- cgit v1.2.3 From 6962b055a1c8db217786c70ebbb907fddc9ba462 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:32 +0100 Subject: spi: stm32: remove SPI LOOP mode This driver does not support SPI LOOP mode by configuration in registers. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index f7056b767477..b639be752fe6 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1143,7 +1143,7 @@ static int stm32_spi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; master->bus_num = pdev->id; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | - SPI_3WIRE | SPI_LOOP; + SPI_3WIRE; master->bits_per_word_mask = stm32_spi_get_bpw_mask(spi); master->max_speed_hz = spi->clk_rate / SPI_MBR_DIV_MIN; master->min_speed_hz = spi->clk_rate / SPI_MBR_DIV_MAX; -- cgit v1.2.3 From 8602663096ce671802c1b90272f798a827dbe45d Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:33 +0100 Subject: spi: stm32: rename STM32 SPI registers to STM32H7 Rename STM32 SPI registers to be related to STM32H7 SPI driver and not STM32 generally. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 381 +++++++++++++++++++++++++----------------------- 1 file changed, 199 insertions(+), 182 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index b639be752fe6..2ece69a75ae4 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -20,86 +20,86 @@ #define DRIVER_NAME "spi_stm32" -/* STM32 SPI registers */ -#define STM32_SPI_CR1 0x00 -#define STM32_SPI_CR2 0x04 -#define STM32_SPI_CFG1 0x08 -#define STM32_SPI_CFG2 0x0C -#define STM32_SPI_IER 0x10 -#define STM32_SPI_SR 0x14 -#define STM32_SPI_IFCR 0x18 -#define STM32_SPI_TXDR 0x20 -#define STM32_SPI_RXDR 0x30 -#define STM32_SPI_I2SCFGR 0x50 - -/* STM32_SPI_CR1 bit fields */ -#define SPI_CR1_SPE BIT(0) -#define SPI_CR1_MASRX BIT(8) -#define SPI_CR1_CSTART BIT(9) -#define SPI_CR1_CSUSP BIT(10) -#define SPI_CR1_HDDIR BIT(11) -#define SPI_CR1_SSI BIT(12) - -/* STM32_SPI_CR2 bit fields */ -#define SPI_CR2_TSIZE_SHIFT 0 -#define SPI_CR2_TSIZE GENMASK(15, 0) - -/* STM32_SPI_CFG1 bit fields */ -#define SPI_CFG1_DSIZE_SHIFT 0 -#define SPI_CFG1_DSIZE GENMASK(4, 0) -#define SPI_CFG1_FTHLV_SHIFT 5 -#define SPI_CFG1_FTHLV GENMASK(8, 5) -#define SPI_CFG1_RXDMAEN BIT(14) -#define SPI_CFG1_TXDMAEN BIT(15) -#define SPI_CFG1_MBR_SHIFT 28 -#define SPI_CFG1_MBR GENMASK(30, 28) -#define SPI_CFG1_MBR_MIN 0 -#define SPI_CFG1_MBR_MAX (GENMASK(30, 28) >> 28) - -/* STM32_SPI_CFG2 bit fields */ -#define SPI_CFG2_MIDI_SHIFT 4 -#define SPI_CFG2_MIDI GENMASK(7, 4) -#define SPI_CFG2_COMM_SHIFT 17 -#define SPI_CFG2_COMM GENMASK(18, 17) -#define SPI_CFG2_SP_SHIFT 19 -#define SPI_CFG2_SP GENMASK(21, 19) -#define SPI_CFG2_MASTER BIT(22) -#define SPI_CFG2_LSBFRST BIT(23) -#define SPI_CFG2_CPHA BIT(24) -#define SPI_CFG2_CPOL BIT(25) -#define SPI_CFG2_SSM BIT(26) -#define SPI_CFG2_AFCNTR BIT(31) - -/* STM32_SPI_IER bit fields */ -#define SPI_IER_RXPIE BIT(0) -#define SPI_IER_TXPIE BIT(1) -#define SPI_IER_DXPIE BIT(2) -#define SPI_IER_EOTIE BIT(3) -#define SPI_IER_TXTFIE BIT(4) -#define SPI_IER_OVRIE BIT(6) -#define SPI_IER_MODFIE BIT(9) -#define SPI_IER_ALL GENMASK(10, 0) - -/* STM32_SPI_SR bit fields */ -#define SPI_SR_RXP BIT(0) -#define SPI_SR_TXP BIT(1) -#define SPI_SR_EOT BIT(3) -#define SPI_SR_OVR BIT(6) -#define SPI_SR_MODF BIT(9) -#define SPI_SR_SUSP BIT(11) -#define SPI_SR_RXPLVL_SHIFT 13 -#define SPI_SR_RXPLVL GENMASK(14, 13) -#define SPI_SR_RXWNE BIT(15) - -/* STM32_SPI_IFCR bit fields */ -#define SPI_IFCR_ALL GENMASK(11, 3) - -/* STM32_SPI_I2SCFGR bit fields */ -#define SPI_I2SCFGR_I2SMOD BIT(0) - -/* SPI Master Baud Rate min/max divisor */ -#define SPI_MBR_DIV_MIN (2 << SPI_CFG1_MBR_MIN) -#define SPI_MBR_DIV_MAX (2 << SPI_CFG1_MBR_MAX) +/* STM32H7 SPI registers */ +#define STM32H7_SPI_CR1 0x00 +#define STM32H7_SPI_CR2 0x04 +#define STM32H7_SPI_CFG1 0x08 +#define STM32H7_SPI_CFG2 0x0C +#define STM32H7_SPI_IER 0x10 +#define STM32H7_SPI_SR 0x14 +#define STM32H7_SPI_IFCR 0x18 +#define STM32H7_SPI_TXDR 0x20 +#define STM32H7_SPI_RXDR 0x30 +#define STM32H7_SPI_I2SCFGR 0x50 + +/* STM32H7_SPI_CR1 bit fields */ +#define STM32H7_SPI_CR1_SPE BIT(0) +#define STM32H7_SPI_CR1_MASRX BIT(8) +#define STM32H7_SPI_CR1_CSTART BIT(9) +#define STM32H7_SPI_CR1_CSUSP BIT(10) +#define STM32H7_SPI_CR1_HDDIR BIT(11) +#define STM32H7_SPI_CR1_SSI BIT(12) + +/* STM32H7_SPI_CR2 bit fields */ +#define STM32H7_SPI_CR2_TSIZE_SHIFT 0 +#define STM32H7_SPI_CR2_TSIZE GENMASK(15, 0) + +/* STM32H7_SPI_CFG1 bit fields */ +#define STM32H7_SPI_CFG1_DSIZE_SHIFT 0 +#define STM32H7_SPI_CFG1_DSIZE GENMASK(4, 0) +#define STM32H7_SPI_CFG1_FTHLV_SHIFT 5 +#define STM32H7_SPI_CFG1_FTHLV GENMASK(8, 5) +#define STM32H7_SPI_CFG1_RXDMAEN BIT(14) +#define STM32H7_SPI_CFG1_TXDMAEN BIT(15) +#define STM32H7_SPI_CFG1_MBR_SHIFT 28 +#define STM32H7_SPI_CFG1_MBR GENMASK(30, 28) +#define STM32H7_SPI_CFG1_MBR_MIN 0 +#define STM32H7_SPI_CFG1_MBR_MAX (GENMASK(30, 28) >> 28) + +/* STM32H7_SPI_CFG2 bit fields */ +#define STM32H7_SPI_CFG2_MIDI_SHIFT 4 +#define STM32H7_SPI_CFG2_MIDI GENMASK(7, 4) +#define STM32H7_SPI_CFG2_COMM_SHIFT 17 +#define STM32H7_SPI_CFG2_COMM GENMASK(18, 17) +#define STM32H7_SPI_CFG2_SP_SHIFT 19 +#define STM32H7_SPI_CFG2_SP GENMASK(21, 19) +#define STM32H7_SPI_CFG2_MASTER BIT(22) +#define STM32H7_SPI_CFG2_LSBFRST BIT(23) +#define STM32H7_SPI_CFG2_CPHA BIT(24) +#define STM32H7_SPI_CFG2_CPOL BIT(25) +#define STM32H7_SPI_CFG2_SSM BIT(26) +#define STM32H7_SPI_CFG2_AFCNTR BIT(31) + +/* STM32H7_SPI_IER bit fields */ +#define STM32H7_SPI_IER_RXPIE BIT(0) +#define STM32H7_SPI_IER_TXPIE BIT(1) +#define STM32H7_SPI_IER_DXPIE BIT(2) +#define STM32H7_SPI_IER_EOTIE BIT(3) +#define STM32H7_SPI_IER_TXTFIE BIT(4) +#define STM32H7_SPI_IER_OVRIE BIT(6) +#define STM32H7_SPI_IER_MODFIE BIT(9) +#define STM32H7_SPI_IER_ALL GENMASK(10, 0) + +/* STM32H7_SPI_SR bit fields */ +#define STM32H7_SPI_SR_RXP BIT(0) +#define STM32H7_SPI_SR_TXP BIT(1) +#define STM32H7_SPI_SR_EOT BIT(3) +#define STM32H7_SPI_SR_OVR BIT(6) +#define STM32H7_SPI_SR_MODF BIT(9) +#define STM32H7_SPI_SR_SUSP BIT(11) +#define STM32H7_SPI_SR_RXPLVL_SHIFT 13 +#define STM32H7_SPI_SR_RXPLVL GENMASK(14, 13) +#define STM32H7_SPI_SR_RXWNE BIT(15) + +/* STM32H7_SPI_IFCR bit fields */ +#define STM32H7_SPI_IFCR_ALL GENMASK(11, 3) + +/* STM32H7_SPI_I2SCFGR bit fields */ +#define STM32H7_SPI_I2SCFGR_I2SMOD BIT(0) + +/* STM32H7 SPI Master Baud Rate min/max divisor */ +#define STM32H7_SPI_MBR_DIV_MIN (2 << STM32H7_SPI_CFG1_MBR_MIN) +#define STM32H7_SPI_MBR_DIV_MAX (2 << STM32H7_SPI_CFG1_MBR_MAX) /* SPI Communication mode */ #define SPI_FULL_DUPLEX 0 @@ -188,12 +188,12 @@ static int stm32_spi_get_fifo_size(struct stm32_spi *spi) spin_lock_irqsave(&spi->lock, flags); - stm32_spi_set_bits(spi, STM32_SPI_CR1, SPI_CR1_SPE); + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE); - while (readl_relaxed(spi->base + STM32_SPI_SR) & SPI_SR_TXP) - writeb_relaxed(++count, spi->base + STM32_SPI_TXDR); + while (readl_relaxed(spi->base + STM32H7_SPI_SR) & STM32H7_SPI_SR_TXP) + writeb_relaxed(++count, spi->base + STM32H7_SPI_TXDR); - stm32_spi_clr_bits(spi, STM32_SPI_CR1, SPI_CR1_SPE); + stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE); spin_unlock_irqrestore(&spi->lock, flags); @@ -217,10 +217,11 @@ static int stm32_spi_get_bpw_mask(struct stm32_spi *spi) * The most significant bit at DSIZE bit field is reserved when the * maximum data size of periperal instances is limited to 16-bit */ - stm32_spi_set_bits(spi, STM32_SPI_CFG1, SPI_CFG1_DSIZE); + stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_DSIZE); - cfg1 = readl_relaxed(spi->base + STM32_SPI_CFG1); - max_bpw = (cfg1 & SPI_CFG1_DSIZE) >> SPI_CFG1_DSIZE_SHIFT; + cfg1 = readl_relaxed(spi->base + STM32H7_SPI_CFG1); + max_bpw = (cfg1 & STM32H7_SPI_CFG1_DSIZE) >> + STM32H7_SPI_CFG1_DSIZE_SHIFT; max_bpw += 1; spin_unlock_irqrestore(&spi->lock, flags); @@ -250,8 +251,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz) * no need to check it there. * However, we need to ensure the following calculations. */ - if (div < SPI_MBR_DIV_MIN || - div > SPI_MBR_DIV_MAX) + if (div < STM32H7_SPI_MBR_DIV_MIN || + div > STM32H7_SPI_MBR_DIV_MAX) return -EINVAL; /* Determine the first power of 2 greater than or equal to div */ @@ -302,23 +303,24 @@ static u32 stm32_spi_prepare_fthlv(struct stm32_spi *spi) static void stm32_spi_write_txfifo(struct stm32_spi *spi) { while ((spi->tx_len > 0) && - (readl_relaxed(spi->base + STM32_SPI_SR) & SPI_SR_TXP)) { + (readl_relaxed(spi->base + STM32H7_SPI_SR) & + STM32H7_SPI_SR_TXP)) { u32 offs = spi->cur_xferlen - spi->tx_len; if (spi->tx_len >= sizeof(u32)) { const u32 *tx_buf32 = (const u32 *)(spi->tx_buf + offs); - writel_relaxed(*tx_buf32, spi->base + STM32_SPI_TXDR); + writel_relaxed(*tx_buf32, spi->base + STM32H7_SPI_TXDR); spi->tx_len -= sizeof(u32); } else if (spi->tx_len >= sizeof(u16)) { const u16 *tx_buf16 = (const u16 *)(spi->tx_buf + offs); - writew_relaxed(*tx_buf16, spi->base + STM32_SPI_TXDR); + writew_relaxed(*tx_buf16, spi->base + STM32H7_SPI_TXDR); spi->tx_len -= sizeof(u16); } else { const u8 *tx_buf8 = (const u8 *)(spi->tx_buf + offs); - writeb_relaxed(*tx_buf8, spi->base + STM32_SPI_TXDR); + writeb_relaxed(*tx_buf8, spi->base + STM32H7_SPI_TXDR); spi->tx_len -= sizeof(u8); } } @@ -335,35 +337,37 @@ static void stm32_spi_write_txfifo(struct stm32_spi *spi) */ static void stm32_spi_read_rxfifo(struct stm32_spi *spi, bool flush) { - u32 sr = readl_relaxed(spi->base + STM32_SPI_SR); - u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR); + u32 rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> + STM32H7_SPI_SR_RXPLVL_SHIFT; while ((spi->rx_len > 0) && - ((sr & SPI_SR_RXP) || - (flush && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) { + ((sr & STM32H7_SPI_SR_RXP) || + (flush && ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { u32 offs = spi->cur_xferlen - spi->rx_len; if ((spi->rx_len >= sizeof(u32)) || - (flush && (sr & SPI_SR_RXWNE))) { + (flush && (sr & STM32H7_SPI_SR_RXWNE))) { u32 *rx_buf32 = (u32 *)(spi->rx_buf + offs); - *rx_buf32 = readl_relaxed(spi->base + STM32_SPI_RXDR); + *rx_buf32 = readl_relaxed(spi->base + STM32H7_SPI_RXDR); spi->rx_len -= sizeof(u32); } else if ((spi->rx_len >= sizeof(u16)) || (flush && (rxplvl >= 2 || spi->cur_bpw > 8))) { u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); - *rx_buf16 = readw_relaxed(spi->base + STM32_SPI_RXDR); + *rx_buf16 = readw_relaxed(spi->base + STM32H7_SPI_RXDR); spi->rx_len -= sizeof(u16); } else { u8 *rx_buf8 = (u8 *)(spi->rx_buf + offs); - *rx_buf8 = readb_relaxed(spi->base + STM32_SPI_RXDR); + *rx_buf8 = readb_relaxed(spi->base + STM32H7_SPI_RXDR); spi->rx_len -= sizeof(u8); } - sr = readl_relaxed(spi->base + STM32_SPI_SR); - rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + sr = readl_relaxed(spi->base + STM32H7_SPI_SR); + rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> + STM32H7_SPI_SR_RXPLVL_SHIFT; } dev_dbg(spi->dev, "%s%s: %d bytes left\n", __func__, @@ -381,7 +385,7 @@ static void stm32_spi_enable(struct stm32_spi *spi) { dev_dbg(spi->dev, "enable controller\n"); - stm32_spi_set_bits(spi, STM32_SPI_CR1, SPI_CR1_SPE); + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE); } /** @@ -401,23 +405,23 @@ static void stm32_spi_disable(struct stm32_spi *spi) spin_lock_irqsave(&spi->lock, flags); - cr1 = readl_relaxed(spi->base + STM32_SPI_CR1); + cr1 = readl_relaxed(spi->base + STM32H7_SPI_CR1); - if (!(cr1 & SPI_CR1_SPE)) { + if (!(cr1 & STM32H7_SPI_CR1_SPE)) { spin_unlock_irqrestore(&spi->lock, flags); return; } /* Wait on EOT or suspend the flow */ - if (readl_relaxed_poll_timeout_atomic(spi->base + STM32_SPI_SR, - sr, !(sr & SPI_SR_EOT), + if (readl_relaxed_poll_timeout_atomic(spi->base + STM32H7_SPI_SR, + sr, !(sr & STM32H7_SPI_SR_EOT), 10, 100000) < 0) { - if (cr1 & SPI_CR1_CSTART) { - writel_relaxed(cr1 | SPI_CR1_CSUSP, - spi->base + STM32_SPI_CR1); + if (cr1 & STM32H7_SPI_CR1_CSTART) { + writel_relaxed(cr1 | STM32H7_SPI_CR1_CSUSP, + spi->base + STM32H7_SPI_CR1); if (readl_relaxed_poll_timeout_atomic( - spi->base + STM32_SPI_SR, - sr, !(sr & SPI_SR_SUSP), + spi->base + STM32H7_SPI_SR, + sr, !(sr & STM32H7_SPI_SR_SUSP), 10, 100000) < 0) dev_warn(spi->dev, "Suspend request timeout\n"); @@ -432,14 +436,14 @@ static void stm32_spi_disable(struct stm32_spi *spi) if (spi->cur_usedma && spi->dma_rx) dmaengine_terminate_all(spi->dma_rx); - stm32_spi_clr_bits(spi, STM32_SPI_CR1, SPI_CR1_SPE); + stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE); - stm32_spi_clr_bits(spi, STM32_SPI_CFG1, SPI_CFG1_TXDMAEN | - SPI_CFG1_RXDMAEN); + stm32_spi_clr_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_TXDMAEN | + STM32H7_SPI_CFG1_RXDMAEN); /* Disable interrupts and clear status flags */ - writel_relaxed(0, spi->base + STM32_SPI_IER); - writel_relaxed(SPI_IFCR_ALL, spi->base + STM32_SPI_IFCR); + writel_relaxed(0, spi->base + STM32H7_SPI_IER); + writel_relaxed(STM32H7_SPI_IFCR_ALL, spi->base + STM32H7_SPI_IFCR); spin_unlock_irqrestore(&spi->lock, flags); } @@ -476,19 +480,19 @@ static irqreturn_t stm32_spi_irq(int irq, void *dev_id) spin_lock_irqsave(&spi->lock, flags); - sr = readl_relaxed(spi->base + STM32_SPI_SR); - ier = readl_relaxed(spi->base + STM32_SPI_IER); + sr = readl_relaxed(spi->base + STM32H7_SPI_SR); + ier = readl_relaxed(spi->base + STM32H7_SPI_IER); mask = ier; /* EOTIE is triggered on EOT, SUSP and TXC events. */ - mask |= SPI_SR_SUSP; + mask |= STM32H7_SPI_SR_SUSP; /* * When TXTF is set, DXPIE and TXPIE are cleared. So in case of * Full-Duplex, need to poll RXP event to know if there are remaining * data, before disabling SPI. */ if (spi->rx_buf && !spi->cur_usedma) - mask |= SPI_SR_RXP; + mask |= STM32H7_SPI_SR_RXP; if (!(sr & mask)) { dev_dbg(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", @@ -497,7 +501,7 @@ static irqreturn_t stm32_spi_irq(int irq, void *dev_id) return IRQ_NONE; } - if (sr & SPI_SR_SUSP) { + if (sr & STM32H7_SPI_SR_SUSP) { dev_warn(spi->dev, "Communication suspended\n"); if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) stm32_spi_read_rxfifo(spi, false); @@ -509,12 +513,12 @@ static irqreturn_t stm32_spi_irq(int irq, void *dev_id) end = true; } - if (sr & SPI_SR_MODF) { + if (sr & STM32H7_SPI_SR_MODF) { dev_warn(spi->dev, "Mode fault: transfer aborted\n"); end = true; } - if (sr & SPI_SR_OVR) { + if (sr & STM32H7_SPI_SR_OVR) { dev_warn(spi->dev, "Overrun: received value discarded\n"); if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) stm32_spi_read_rxfifo(spi, false); @@ -526,21 +530,21 @@ static irqreturn_t stm32_spi_irq(int irq, void *dev_id) end = true; } - if (sr & SPI_SR_EOT) { + if (sr & STM32H7_SPI_SR_EOT) { if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) stm32_spi_read_rxfifo(spi, true); end = true; } - if (sr & SPI_SR_TXP) + if (sr & STM32H7_SPI_SR_TXP) if (!spi->cur_usedma && (spi->tx_buf && (spi->tx_len > 0))) stm32_spi_write_txfifo(spi); - if (sr & SPI_SR_RXP) + if (sr & STM32H7_SPI_SR_RXP) if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) stm32_spi_read_rxfifo(spi, false); - writel_relaxed(mask, spi->base + STM32_SPI_IFCR); + writel_relaxed(mask, spi->base + STM32H7_SPI_IFCR); spin_unlock_irqrestore(&spi->lock, flags); @@ -593,19 +597,19 @@ static int stm32_spi_prepare_msg(struct spi_master *master, dev_dbg(spi->dev, "%dns inter-data idleness\n", spi->cur_midi); if (spi_dev->mode & SPI_CPOL) - cfg2_setb |= SPI_CFG2_CPOL; + cfg2_setb |= STM32H7_SPI_CFG2_CPOL; else - cfg2_clrb |= SPI_CFG2_CPOL; + cfg2_clrb |= STM32H7_SPI_CFG2_CPOL; if (spi_dev->mode & SPI_CPHA) - cfg2_setb |= SPI_CFG2_CPHA; + cfg2_setb |= STM32H7_SPI_CFG2_CPHA; else - cfg2_clrb |= SPI_CFG2_CPHA; + cfg2_clrb |= STM32H7_SPI_CFG2_CPHA; if (spi_dev->mode & SPI_LSB_FIRST) - cfg2_setb |= SPI_CFG2_LSBFRST; + cfg2_setb |= STM32H7_SPI_CFG2_LSBFRST; else - cfg2_clrb |= SPI_CFG2_LSBFRST; + cfg2_clrb |= STM32H7_SPI_CFG2_LSBFRST; dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d\n", spi_dev->mode & SPI_CPOL, @@ -617,9 +621,9 @@ static int stm32_spi_prepare_msg(struct spi_master *master, if (cfg2_clrb || cfg2_setb) writel_relaxed( - (readl_relaxed(spi->base + STM32_SPI_CFG2) & + (readl_relaxed(spi->base + STM32H7_SPI_CFG2) & ~cfg2_clrb) | cfg2_setb, - spi->base + STM32_SPI_CFG2); + spi->base + STM32H7_SPI_CFG2); spin_unlock_irqrestore(&spi->lock, flags); @@ -640,11 +644,11 @@ static void stm32_spi_dma_cb(void *data) spin_lock_irqsave(&spi->lock, flags); - sr = readl_relaxed(spi->base + STM32_SPI_SR); + sr = readl_relaxed(spi->base + STM32H7_SPI_SR); spin_unlock_irqrestore(&spi->lock, flags); - if (!(sr & SPI_SR_EOT)) + if (!(sr & STM32H7_SPI_SR_EOT)) dev_warn(spi->dev, "DMA error (sr=0x%08x)\n", sr); /* Now wait for EOT, or SUSP or OVR in case of error */ @@ -677,14 +681,14 @@ static void stm32_spi_dma_config(struct stm32_spi *spi, memset(dma_conf, 0, sizeof(struct dma_slave_config)); dma_conf->direction = dir; if (dma_conf->direction == DMA_DEV_TO_MEM) { /* RX */ - dma_conf->src_addr = spi->phys_addr + STM32_SPI_RXDR; + dma_conf->src_addr = spi->phys_addr + STM32H7_SPI_RXDR; dma_conf->src_addr_width = buswidth; dma_conf->src_maxburst = maxburst; dev_dbg(spi->dev, "Rx DMA config buswidth=%d, maxburst=%d\n", buswidth, maxburst); } else if (dma_conf->direction == DMA_MEM_TO_DEV) { /* TX */ - dma_conf->dst_addr = spi->phys_addr + STM32_SPI_TXDR; + dma_conf->dst_addr = spi->phys_addr + STM32H7_SPI_TXDR; dma_conf->dst_addr_width = buswidth; dma_conf->dst_maxburst = maxburst; @@ -707,14 +711,15 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) /* Enable the interrupts relative to the current communication mode */ if (spi->tx_buf && spi->rx_buf) /* Full Duplex */ - ier |= SPI_IER_DXPIE; + ier |= STM32H7_SPI_IER_DXPIE; else if (spi->tx_buf) /* Half-Duplex TX dir or Simplex TX */ - ier |= SPI_IER_TXPIE; + ier |= STM32H7_SPI_IER_TXPIE; else if (spi->rx_buf) /* Half-Duplex RX dir or Simplex RX */ - ier |= SPI_IER_RXPIE; + ier |= STM32H7_SPI_IER_RXPIE; /* Enable the interrupts relative to the end of transfer */ - ier |= SPI_IER_EOTIE | SPI_IER_TXTFIE | SPI_IER_OVRIE | SPI_IER_MODFIE; + ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | + STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; spin_lock_irqsave(&spi->lock, flags); @@ -724,9 +729,9 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) if (spi->tx_buf) stm32_spi_write_txfifo(spi); - stm32_spi_set_bits(spi, STM32_SPI_CR1, SPI_CR1_CSTART); + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); - writel_relaxed(ier, spi->base + STM32_SPI_IER); + writel_relaxed(ier, spi->base + STM32H7_SPI_IER); spin_unlock_irqrestore(&spi->lock, flags); @@ -755,7 +760,8 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, dmaengine_slave_config(spi->dma_rx, &rx_dma_conf); /* Enable Rx DMA request */ - stm32_spi_set_bits(spi, STM32_SPI_CFG1, SPI_CFG1_RXDMAEN); + stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, + STM32H7_SPI_CFG1_RXDMAEN); rx_dma_desc = dmaengine_prep_slave_sg( spi->dma_rx, xfer->rx_sg.sgl, @@ -809,16 +815,18 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, dma_async_issue_pending(spi->dma_tx); /* Enable Tx DMA request */ - stm32_spi_set_bits(spi, STM32_SPI_CFG1, SPI_CFG1_TXDMAEN); + stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, + STM32H7_SPI_CFG1_TXDMAEN); } /* Enable the interrupts relative to the end of transfer */ - ier |= SPI_IER_EOTIE | SPI_IER_TXTFIE | SPI_IER_OVRIE | SPI_IER_MODFIE; - writel_relaxed(ier, spi->base + STM32_SPI_IER); + ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | + STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; + writel_relaxed(ier, spi->base + STM32H7_SPI_IER); stm32_spi_enable(spi); - stm32_spi_set_bits(spi, STM32_SPI_CR1, SPI_CR1_CSTART); + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); spin_unlock_irqrestore(&spi->lock, flags); @@ -829,7 +837,7 @@ dma_submit_error: dmaengine_terminate_all(spi->dma_rx); dma_desc_error: - stm32_spi_clr_bits(spi, STM32_SPI_CFG1, SPI_CFG1_RXDMAEN); + stm32_spi_clr_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_RXDMAEN); spin_unlock_irqrestore(&spi->lock, flags); @@ -861,14 +869,16 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, spi->cur_bpw = transfer->bits_per_word; bpw = spi->cur_bpw - 1; - cfg1_clrb |= SPI_CFG1_DSIZE; - cfg1_setb |= (bpw << SPI_CFG1_DSIZE_SHIFT) & SPI_CFG1_DSIZE; + cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE; + cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & + STM32H7_SPI_CFG1_DSIZE; spi->cur_fthlv = stm32_spi_prepare_fthlv(spi); fthlv = spi->cur_fthlv - 1; - cfg1_clrb |= SPI_CFG1_FTHLV; - cfg1_setb |= (fthlv << SPI_CFG1_FTHLV_SHIFT) & SPI_CFG1_FTHLV; + cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; + cfg1_setb |= (fthlv << STM32H7_SPI_CFG1_FTHLV_SHIFT) & + STM32H7_SPI_CFG1_FTHLV; } if (spi->cur_speed != transfer->speed_hz) { @@ -883,14 +893,15 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, transfer->speed_hz = spi->cur_speed; - cfg1_clrb |= SPI_CFG1_MBR; - cfg1_setb |= ((u32)mbr << SPI_CFG1_MBR_SHIFT) & SPI_CFG1_MBR; + cfg1_clrb |= STM32H7_SPI_CFG1_MBR; + cfg1_setb |= ((u32)mbr << STM32H7_SPI_CFG1_MBR_SHIFT) & + STM32H7_SPI_CFG1_MBR; } if (cfg1_clrb || cfg1_setb) - writel_relaxed((readl_relaxed(spi->base + STM32_SPI_CFG1) & + writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG1) & ~cfg1_clrb) | cfg1_setb, - spi->base + STM32_SPI_CFG1); + spi->base + STM32H7_SPI_CFG1); mode = SPI_FULL_DUPLEX; if (spi_dev->mode & SPI_3WIRE) { /* MISO/MOSI signals shared */ @@ -902,9 +913,11 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, */ mode = SPI_HALF_DUPLEX; if (!transfer->tx_buf) - stm32_spi_clr_bits(spi, STM32_SPI_CR1, SPI_CR1_HDDIR); + stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, + STM32H7_SPI_CR1_HDDIR); else if (!transfer->rx_buf) - stm32_spi_set_bits(spi, STM32_SPI_CR1, SPI_CR1_HDDIR); + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, + STM32H7_SPI_CR1_HDDIR); } else { if (!transfer->tx_buf) mode = SPI_SIMPLEX_RX; @@ -914,26 +927,29 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, if (spi->cur_comm != mode) { spi->cur_comm = mode; - cfg2_clrb |= SPI_CFG2_COMM; - cfg2_setb |= (mode << SPI_CFG2_COMM_SHIFT) & SPI_CFG2_COMM; + cfg2_clrb |= STM32H7_SPI_CFG2_COMM; + cfg2_setb |= (mode << STM32H7_SPI_CFG2_COMM_SHIFT) & + STM32H7_SPI_CFG2_COMM; } - cfg2_clrb |= SPI_CFG2_MIDI; + cfg2_clrb |= STM32H7_SPI_CFG2_MIDI; if ((transfer->len > 1) && (spi->cur_midi > 0)) { u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed); u32 midi = min((u32)DIV_ROUND_UP(spi->cur_midi, sck_period_ns), - (u32)SPI_CFG2_MIDI >> SPI_CFG2_MIDI_SHIFT); + (u32)STM32H7_SPI_CFG2_MIDI >> + STM32H7_SPI_CFG2_MIDI_SHIFT); dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n", sck_period_ns, midi, midi * sck_period_ns); - cfg2_setb |= (midi << SPI_CFG2_MIDI_SHIFT) & SPI_CFG2_MIDI; + cfg2_setb |= (midi << STM32H7_SPI_CFG2_MIDI_SHIFT) & + STM32H7_SPI_CFG2_MIDI; } if (cfg2_clrb || cfg2_setb) - writel_relaxed((readl_relaxed(spi->base + STM32_SPI_CFG2) & + writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) & ~cfg2_clrb) | cfg2_setb, - spi->base + STM32_SPI_CFG2); + spi->base + STM32H7_SPI_CFG2); if (spi->cur_bpw <= 8) nb_words = transfer->len; @@ -941,10 +957,10 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, nb_words = DIV_ROUND_UP(transfer->len * 8, 16); else nb_words = DIV_ROUND_UP(transfer->len * 8, 32); - nb_words <<= SPI_CR2_TSIZE_SHIFT; + nb_words <<= STM32H7_SPI_CR2_TSIZE_SHIFT; - if (nb_words <= SPI_CR2_TSIZE) { - writel_relaxed(nb_words, spi->base + STM32_SPI_CR2); + if (nb_words <= STM32H7_SPI_CR2_TSIZE) { + writel_relaxed(nb_words, spi->base + STM32H7_SPI_CR2); } else { ret = -EMSGSIZE; goto out; @@ -1030,16 +1046,17 @@ static int stm32_spi_config(struct stm32_spi *spi) spin_lock_irqsave(&spi->lock, flags); /* Ensure I2SMOD bit is kept cleared */ - stm32_spi_clr_bits(spi, STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD); + stm32_spi_clr_bits(spi, STM32H7_SPI_I2SCFGR, + STM32H7_SPI_I2SCFGR_I2SMOD); /* * - SS input value high * - transmitter half duplex direction * - automatic communication suspend when RX-Fifo is full */ - stm32_spi_set_bits(spi, STM32_SPI_CR1, SPI_CR1_SSI | - SPI_CR1_HDDIR | - SPI_CR1_MASRX); + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SSI | + STM32H7_SPI_CR1_HDDIR | + STM32H7_SPI_CR1_MASRX); /* * - Set the master mode (default Motorola mode) @@ -1047,9 +1064,9 @@ static int stm32_spi_config(struct stm32_spi *spi) * SS input value is determined by the SSI bit * - keep control of all associated GPIOs */ - stm32_spi_set_bits(spi, STM32_SPI_CFG2, SPI_CFG2_MASTER | - SPI_CFG2_SSM | - SPI_CFG2_AFCNTR); + stm32_spi_set_bits(spi, STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_MASTER | + STM32H7_SPI_CFG2_SSM | + STM32H7_SPI_CFG2_AFCNTR); spin_unlock_irqrestore(&spi->lock, flags); @@ -1145,8 +1162,8 @@ static int stm32_spi_probe(struct platform_device *pdev) master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE; master->bits_per_word_mask = stm32_spi_get_bpw_mask(spi); - master->max_speed_hz = spi->clk_rate / SPI_MBR_DIV_MIN; - master->min_speed_hz = spi->clk_rate / SPI_MBR_DIV_MAX; + master->max_speed_hz = spi->clk_rate / STM32H7_SPI_MBR_DIV_MIN; + master->min_speed_hz = spi->clk_rate / STM32H7_SPI_MBR_DIV_MAX; master->setup = stm32_spi_setup; master->prepare_message = stm32_spi_prepare_msg; master->transfer_one = stm32_spi_transfer_one; -- cgit v1.2.3 From a9675337ad3e540cecb2411a7fc71fda133a3932 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:34 +0100 Subject: spi: stm32: rename interrupt function Interrupt function is used as a thread so rename it to express meaning directly by more clear function name. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 2ece69a75ae4..9cb7d334a5cb 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -466,11 +466,11 @@ static bool stm32_spi_can_dma(struct spi_master *master, } /** - * stm32_spi_irq - Interrupt handler for SPI controller events + * stm32_spi_irq_thread - Thread of interrupt handler for SPI controller * @irq: interrupt line * @dev_id: SPI controller master interface */ -static irqreturn_t stm32_spi_irq(int irq, void *dev_id) +static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id) { struct spi_master *master = dev_id; struct stm32_spi *spi = spi_master_get_devdata(master); @@ -1113,7 +1113,7 @@ static int stm32_spi_probe(struct platform_device *pdev) goto err_master_put; } ret = devm_request_threaded_irq(&pdev->dev, spi->irq, NULL, - stm32_spi_irq, IRQF_ONESHOT, + stm32_spi_irq_thread, IRQF_ONESHOT, pdev->name, master); if (ret) { dev_err(&pdev->dev, "irq%d request failed: %d\n", spi->irq, -- cgit v1.2.3 From 9d5fce166c7a26ed9811f9b0ae914a079e62c0f8 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:35 +0100 Subject: spi: stm32: split transfer one setup function Split stm32_spi_transfer_one_setup function into smaller chunks to be more generic for other stm32 SPI family drivers. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 270 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 192 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 9cb7d334a5cb..bc8513f088aa 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -101,11 +101,18 @@ #define STM32H7_SPI_MBR_DIV_MIN (2 << STM32H7_SPI_CFG1_MBR_MIN) #define STM32H7_SPI_MBR_DIV_MAX (2 << STM32H7_SPI_CFG1_MBR_MAX) -/* SPI Communication mode */ +/* STM32H7 SPI Communication mode */ +#define STM32H7_SPI_FULL_DUPLEX 0 +#define STM32H7_SPI_SIMPLEX_TX 1 +#define STM32H7_SPI_SIMPLEX_RX 2 +#define STM32H7_SPI_HALF_DUPLEX 3 + +/* SPI Communication type */ #define SPI_FULL_DUPLEX 0 #define SPI_SIMPLEX_TX 1 #define SPI_SIMPLEX_RX 2 -#define SPI_HALF_DUPLEX 3 +#define SPI_3WIRE_TX 3 +#define SPI_3WIRE_RX 4 #define SPI_1HZ_NS 1000000000 @@ -232,13 +239,16 @@ static int stm32_spi_get_bpw_mask(struct stm32_spi *spi) } /** - * stm32_spi_prepare_mbr - Determine SPI_CFG1.MBR value + * stm32_spi_prepare_mbr - Determine baud rate divisor value * @spi: pointer to the spi controller data structure * @speed_hz: requested speed + * @min_div: minimum baud rate divisor + * @max_div: maximum baud rate divisor * - * Return SPI_CFG1.MBR value in case of success or -EINVAL + * Return baud rate divisor value in case of success or -EINVAL */ -static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz) +static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, + u32 min_div, u32 max_div) { u32 div, mbrdiv; @@ -251,8 +261,7 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz) * no need to check it there. * However, we need to ensure the following calculations. */ - if (div < STM32H7_SPI_MBR_DIV_MIN || - div > STM32H7_SPI_MBR_DIV_MAX) + if ((div < min_div) || (div > max_div)) return -EINVAL; /* Determine the first power of 2 greater than or equal to div */ @@ -802,7 +811,8 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, } if (tx_dma_desc) { - if (spi->cur_comm == SPI_SIMPLEX_TX) { + if (spi->cur_comm == SPI_SIMPLEX_TX || + spi->cur_comm == SPI_3WIRE_TX) { tx_dma_desc->callback = stm32_spi_dma_cb; tx_dma_desc->callback_param = spi; } @@ -848,92 +858,130 @@ dma_desc_error: } /** - * stm32_spi_transfer_one_setup - common setup to transfer a single - * spi_transfer either using DMA or - * interrupts. + * stm32_spi_set_bpw - configure bits per word + * @spi: pointer to the spi controller data structure */ -static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, - struct spi_device *spi_dev, - struct spi_transfer *transfer) +static void stm32_spi_set_bpw(struct stm32_spi *spi) { - unsigned long flags; - u32 cfg1_clrb = 0, cfg1_setb = 0, cfg2_clrb = 0, cfg2_setb = 0; - u32 mode, nb_words; - int ret = 0; + u32 bpw, fthlv; + u32 cfg1_clrb = 0, cfg1_setb = 0; - spin_lock_irqsave(&spi->lock, flags); + bpw = spi->cur_bpw - 1; - if (spi->cur_bpw != transfer->bits_per_word) { - u32 bpw, fthlv; - - spi->cur_bpw = transfer->bits_per_word; - bpw = spi->cur_bpw - 1; + cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE; + cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & + STM32H7_SPI_CFG1_DSIZE; - cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE; - cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & - STM32H7_SPI_CFG1_DSIZE; + spi->cur_fthlv = stm32_spi_prepare_fthlv(spi); + fthlv = spi->cur_fthlv - 1; - spi->cur_fthlv = stm32_spi_prepare_fthlv(spi); - fthlv = spi->cur_fthlv - 1; + cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; + cfg1_setb |= (fthlv << STM32H7_SPI_CFG1_FTHLV_SHIFT) & + STM32H7_SPI_CFG1_FTHLV; - cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; - cfg1_setb |= (fthlv << STM32H7_SPI_CFG1_FTHLV_SHIFT) & - STM32H7_SPI_CFG1_FTHLV; - } - - if (spi->cur_speed != transfer->speed_hz) { - int mbr; + writel_relaxed( + (readl_relaxed(spi->base + STM32H7_SPI_CFG1) & + ~cfg1_clrb) | cfg1_setb, + spi->base + STM32H7_SPI_CFG1); +} - /* Update spi->cur_speed with real clock speed */ - mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz); - if (mbr < 0) { - ret = mbr; - goto out; - } +/** + * stm32_spi_set_mbr - Configure baud rate divisor in master mode + * @spi: pointer to the spi controller data structure + * @mbrdiv: baud rate divisor value + */ +static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) +{ + u32 cfg1_clrb = 0, cfg1_setb = 0; - transfer->speed_hz = spi->cur_speed; + cfg1_clrb |= STM32H7_SPI_CFG1_MBR; + cfg1_setb |= ((u32)mbrdiv << STM32H7_SPI_CFG1_MBR_SHIFT) & + STM32H7_SPI_CFG1_MBR; - cfg1_clrb |= STM32H7_SPI_CFG1_MBR; - cfg1_setb |= ((u32)mbr << STM32H7_SPI_CFG1_MBR_SHIFT) & - STM32H7_SPI_CFG1_MBR; - } + writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG1) & + ~cfg1_clrb) | cfg1_setb, + spi->base + STM32H7_SPI_CFG1); +} - if (cfg1_clrb || cfg1_setb) - writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG1) & - ~cfg1_clrb) | cfg1_setb, - spi->base + STM32H7_SPI_CFG1); +/** + * stm32_spi_communication_type - return transfer communication type + * @spi_dev: pointer to the spi device + * transfer: pointer to spi transfer + */ +static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev, + struct spi_transfer *transfer) +{ + unsigned int type = SPI_FULL_DUPLEX; - mode = SPI_FULL_DUPLEX; if (spi_dev->mode & SPI_3WIRE) { /* MISO/MOSI signals shared */ /* * SPI_3WIRE and xfer->tx_buf != NULL and xfer->rx_buf != NULL - * is forbidden und unvalidated by SPI subsystem so depending + * is forbidden and unvalidated by SPI subsystem so depending * on the valid buffer, we can determine the direction of the * transfer. */ - mode = SPI_HALF_DUPLEX; if (!transfer->tx_buf) - stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, - STM32H7_SPI_CR1_HDDIR); - else if (!transfer->rx_buf) - stm32_spi_set_bits(spi, STM32H7_SPI_CR1, - STM32H7_SPI_CR1_HDDIR); + type = SPI_3WIRE_RX; + else + type = SPI_3WIRE_TX; } else { if (!transfer->tx_buf) - mode = SPI_SIMPLEX_RX; + type = SPI_SIMPLEX_RX; else if (!transfer->rx_buf) - mode = SPI_SIMPLEX_TX; + type = SPI_SIMPLEX_TX; } - if (spi->cur_comm != mode) { - spi->cur_comm = mode; - cfg2_clrb |= STM32H7_SPI_CFG2_COMM; - cfg2_setb |= (mode << STM32H7_SPI_CFG2_COMM_SHIFT) & - STM32H7_SPI_CFG2_COMM; + return type; +} + +/** + * stm32_spi_set_mode - configure communication mode + * @spi: pointer to the spi controller data structure + * @comm_type: type of communication to configure + */ +static int stm32_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) +{ + u32 mode; + u32 cfg2_clrb = 0, cfg2_setb = 0; + + if (comm_type == SPI_3WIRE_RX) { + mode = STM32H7_SPI_HALF_DUPLEX; + stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_HDDIR); + } else if (comm_type == SPI_3WIRE_TX) { + mode = STM32H7_SPI_HALF_DUPLEX; + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_HDDIR); + } else if (comm_type == SPI_SIMPLEX_RX) { + mode = STM32H7_SPI_SIMPLEX_RX; + } else if (comm_type == SPI_SIMPLEX_TX) { + mode = STM32H7_SPI_SIMPLEX_TX; + } else { + mode = STM32H7_SPI_FULL_DUPLEX; } + cfg2_clrb |= STM32H7_SPI_CFG2_COMM; + cfg2_setb |= (mode << STM32H7_SPI_CFG2_COMM_SHIFT) & + STM32H7_SPI_CFG2_COMM; + + writel_relaxed( + (readl_relaxed(spi->base + STM32H7_SPI_CFG2) & + ~cfg2_clrb) | cfg2_setb, + spi->base + STM32H7_SPI_CFG2); + + return 0; +} + +/** + * stm32_spi_data_idleness - configure minimum time delay inserted between two + * consecutive data frames in master mode + * @spi: pointer to the spi controller data structure + * @len: transfer len + */ +static void stm32_spi_data_idleness(struct stm32_spi *spi, u32 len) +{ + u32 cfg2_clrb = 0, cfg2_setb = 0; + cfg2_clrb |= STM32H7_SPI_CFG2_MIDI; - if ((transfer->len > 1) && (spi->cur_midi > 0)) { + if ((len > 1) && (spi->cur_midi > 0)) { u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed); u32 midi = min((u32)DIV_ROUND_UP(spi->cur_midi, sck_period_ns), (u32)STM32H7_SPI_CFG2_MIDI >> @@ -941,15 +989,85 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n", sck_period_ns, midi, midi * sck_period_ns); - cfg2_setb |= (midi << STM32H7_SPI_CFG2_MIDI_SHIFT) & STM32H7_SPI_CFG2_MIDI; } - if (cfg2_clrb || cfg2_setb) - writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) & - ~cfg2_clrb) | cfg2_setb, - spi->base + STM32H7_SPI_CFG2); + writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) & + ~cfg2_clrb) | cfg2_setb, + spi->base + STM32H7_SPI_CFG2); +} + +/** + * stm32_spi_number_of_data - configure number of data at current transfer + * @spi: pointer to the spi controller data structure + * @len: transfer length + */ +static int stm32_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) +{ + u32 cr2_clrb = 0, cr2_setb = 0; + + if (nb_words <= (STM32H7_SPI_CR2_TSIZE >> + STM32H7_SPI_CR2_TSIZE_SHIFT)) { + cr2_clrb |= STM32H7_SPI_CR2_TSIZE; + cr2_setb = nb_words << STM32H7_SPI_CR2_TSIZE_SHIFT; + writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CR2) & + ~cr2_clrb) | cr2_setb, + spi->base + STM32H7_SPI_CR2); + } else { + return -EMSGSIZE; + } + + return 0; +} + +/** + * stm32_spi_transfer_one_setup - common setup to transfer a single + * spi_transfer either using DMA or + * interrupts. + */ +static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, + struct spi_device *spi_dev, + struct spi_transfer *transfer) +{ + unsigned long flags; + unsigned int comm_type; + int nb_words, ret = 0; + + spin_lock_irqsave(&spi->lock, flags); + + if (spi->cur_bpw != transfer->bits_per_word) { + spi->cur_bpw = transfer->bits_per_word; + stm32_spi_set_bpw(spi); + } + + if (spi->cur_speed != transfer->speed_hz) { + int mbr; + + /* Update spi->cur_speed with real clock speed */ + mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, + STM32H7_SPI_MBR_DIV_MIN, + STM32H7_SPI_MBR_DIV_MAX); + if (mbr < 0) { + ret = mbr; + goto out; + } + + transfer->speed_hz = spi->cur_speed; + stm32_spi_set_mbr(spi, mbr); + } + + comm_type = stm32_spi_communication_type(spi_dev, transfer); + if (spi->cur_comm != comm_type) { + stm32_spi_set_mode(spi, comm_type); + + if (ret < 0) + goto out; + + spi->cur_comm = comm_type; + } + + stm32_spi_data_idleness(spi, transfer->len); if (spi->cur_bpw <= 8) nb_words = transfer->len; @@ -957,14 +1075,10 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, nb_words = DIV_ROUND_UP(transfer->len * 8, 16); else nb_words = DIV_ROUND_UP(transfer->len * 8, 32); - nb_words <<= STM32H7_SPI_CR2_TSIZE_SHIFT; - if (nb_words <= STM32H7_SPI_CR2_TSIZE) { - writel_relaxed(nb_words, spi->base + STM32H7_SPI_CR2); - } else { - ret = -EMSGSIZE; + ret = stm32_spi_number_of_data(spi, nb_words); + if (ret < 0) goto out; - } spi->cur_xferlen = transfer->len; -- cgit v1.2.3 From f8bb12f2fa4f05c8a957abf4a77e268dd7af2558 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:36 +0100 Subject: spi: stm32: add start dma transfer function Add transfer_one_dma_start function to be more generic for other stm32 SPI family drivers. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index bc8513f088aa..b19d02bf0188 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -747,6 +747,23 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) return 1; } +/** + * stm32_spi_transfer_one_dma_start - Set SPI driver registers to start transfer + * using DMA + */ +static void stm32_spi_transfer_one_dma_start(struct stm32_spi *spi) +{ + /* Enable the interrupts relative to the end of transfer */ + stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE | + STM32H7_SPI_IER_TXTFIE | + STM32H7_SPI_IER_OVRIE | + STM32H7_SPI_IER_MODFIE); + + stm32_spi_enable(spi); + + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); +} + /** * stm32_spi_transfer_one_dma - transfer a single spi_transfer using DMA * @@ -759,7 +776,6 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, struct dma_slave_config tx_dma_conf, rx_dma_conf; struct dma_async_tx_descriptor *tx_dma_desc, *rx_dma_desc; unsigned long flags; - u32 ier = 0; spin_lock_irqsave(&spi->lock, flags); @@ -829,14 +845,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, STM32H7_SPI_CFG1_TXDMAEN); } - /* Enable the interrupts relative to the end of transfer */ - ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | - STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; - writel_relaxed(ier, spi->base + STM32H7_SPI_IER); - - stm32_spi_enable(spi); - - stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); + stm32_spi_transfer_one_dma_start(spi); spin_unlock_irqrestore(&spi->lock, flags); -- cgit v1.2.3 From 55166853b2f56ce29d4f1dad76f092e1a97d9884 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:37 +0100 Subject: spi: stm32: introduce compatible data cfg Prepare support for STM32F4 spi variant by introducing compatible configuration data. Move STM32H7 specific stuff to compatible data structure: - registers & bit fields - routines to control driver - baud rate divisor definitions - fifo availability - split IRQ functions to parts to be called when the IRQ occurs and for threaded interrupt what helps to provide less discontinuous mode for drivers without FIFO. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 337 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 236 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index b19d02bf0188..8b10074cc75f 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -116,10 +116,96 @@ #define SPI_1HZ_NS 1000000000 +/** + * stm32_spi_reg - stm32 SPI register & bitfield desc + * @reg: register offset + * @mask: bitfield mask + * @shift: left shift + */ +struct stm32_spi_reg { + int reg; + int mask; + int shift; +}; + +/** + * stm32_spi_regspec - stm32 registers definition, compatible dependent data + * en: enable register and SPI enable bit + * dma_rx_en: SPI DMA RX enable register end SPI DMA RX enable bit + * dma_tx_en: SPI DMA TX enable register end SPI DMA TX enable bit + * cpol: clock polarity register and polarity bit + * cpha: clock phase register and phase bit + * lsb_first: LSB transmitted first register and bit + * br: baud rate register and bitfields + * rx: SPI RX data register + * tx: SPI TX data register + */ +struct stm32_spi_regspec { + const struct stm32_spi_reg en; + const struct stm32_spi_reg dma_rx_en; + const struct stm32_spi_reg dma_tx_en; + const struct stm32_spi_reg cpol; + const struct stm32_spi_reg cpha; + const struct stm32_spi_reg lsb_first; + const struct stm32_spi_reg br; + const struct stm32_spi_reg rx; + const struct stm32_spi_reg tx; +}; + +struct stm32_spi; + +/** + * stm32_spi_cfg - stm32 compatible configuration data + * @regs: registers descriptions + * @get_fifo_size: routine to get fifo size + * @get_bpw_mask: routine to get bits per word mask + * @disable: routine to disable controller + * @config: routine to configure controller as SPI Master + * @set_bpw: routine to configure registers to for bits per word + * @set_mode: routine to configure registers to desired mode + * @set_data_idleness: optional routine to configure registers to desired idle + * time between frames (if driver has this functionality) + * set_number_of_data: optional routine to configure registers to desired + * number of data (if driver has this functionality) + * @can_dma: routine to determine if the transfer is eligible for DMA use + * @transfer_one_dma_start: routine to start transfer a single spi_transfer + * using DMA + * @dma_rx cb: routine to call after DMA RX channel operation is complete + * @dma_tx cb: routine to call after DMA TX channel operation is complete + * @transfer_one_irq: routine to configure interrupts for driver + * @irq_handler_event: Interrupt handler for SPI controller events + * @irq_handler_thread: thread of interrupt handler for SPI controller + * @baud_rate_div_min: minimum baud rate divisor + * @baud_rate_div_max: maximum baud rate divisor + * @has_fifo: boolean to know if fifo is used for driver + * @has_startbit: boolean to know if start bit is used to start transfer + */ +struct stm32_spi_cfg { + const struct stm32_spi_regspec *regs; + int (*get_fifo_size)(struct stm32_spi *spi); + int (*get_bpw_mask)(struct stm32_spi *spi); + void (*disable)(struct stm32_spi *spi); + int (*config)(struct stm32_spi *spi); + void (*set_bpw)(struct stm32_spi *spi); + int (*set_mode)(struct stm32_spi *spi, unsigned int comm_type); + void (*set_data_idleness)(struct stm32_spi *spi, u32 length); + int (*set_number_of_data)(struct stm32_spi *spi, u32 length); + void (*transfer_one_dma_start)(struct stm32_spi *spi); + void (*dma_rx_cb)(void *data); + void (*dma_tx_cb)(void *data); + int (*transfer_one_irq)(struct stm32_spi *spi); + irqreturn_t (*irq_handler_event)(int irq, void *dev_id); + irqreturn_t (*irq_handler_thread)(int irq, void *dev_id); + unsigned int baud_rate_div_min; + unsigned int baud_rate_div_max; + bool has_fifo; +}; + /** * struct stm32_spi - private data of the SPI controller * @dev: driver model representation of the controller * @master: controller master interface + * @cfg: compatible configuration data * @base: virtual memory area * @clk: hw kernel clock feeding the SPI clock generator * @clk_rate: rate of the hw kernel clock feeding the SPI clock generator @@ -145,6 +231,7 @@ struct stm32_spi { struct device *dev; struct spi_master *master; + const struct stm32_spi_cfg *cfg; void __iomem *base; struct clk *clk; u32 clk_rate; @@ -170,6 +257,25 @@ struct stm32_spi { dma_addr_t phys_addr; }; +static const struct stm32_spi_regspec stm32h7_spi_regspec = { + /* SPI data transfer is enabled but spi_ker_ck is idle. + * CFG1 and CFG2 registers are write protected when SPE is enabled. + */ + .en = { STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE }, + + .dma_rx_en = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_RXDMAEN }, + .dma_tx_en = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_TXDMAEN }, + + .cpol = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPOL }, + .cpha = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPHA }, + .lsb_first = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_LSBFRST }, + .br = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_MBR, + STM32H7_SPI_CFG1_MBR_SHIFT }, + + .rx = { STM32H7_SPI_RXDR }, + .tx = { STM32H7_SPI_TXDR }, +}; + static inline void stm32_spi_set_bits(struct stm32_spi *spi, u32 offset, u32 bits) { @@ -185,10 +291,10 @@ static inline void stm32_spi_clr_bits(struct stm32_spi *spi, } /** - * stm32_spi_get_fifo_size - Return fifo size + * stm32h7_spi_get_fifo_size - Return fifo size * @spi: pointer to the spi controller data structure */ -static int stm32_spi_get_fifo_size(struct stm32_spi *spi) +static int stm32h7_spi_get_fifo_size(struct stm32_spi *spi) { unsigned long flags; u32 count = 0; @@ -210,10 +316,10 @@ static int stm32_spi_get_fifo_size(struct stm32_spi *spi) } /** - * stm32_spi_get_bpw_mask - Return bits per word mask + * stm32h7_spi_get_bpw_mask - Return bits per word mask * @spi: pointer to the spi controller data structure */ -static int stm32_spi_get_bpw_mask(struct stm32_spi *spi) +static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi) { unsigned long flags; u32 cfg1, max_bpw; @@ -276,10 +382,10 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, } /** - * stm32_spi_prepare_fthlv - Determine FIFO threshold level + * stm32h7_spi_prepare_fthlv - Determine FIFO threshold level * @spi: pointer to the spi controller data structure */ -static u32 stm32_spi_prepare_fthlv(struct stm32_spi *spi) +static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) { u32 fthlv, half_fifo; @@ -303,13 +409,13 @@ static u32 stm32_spi_prepare_fthlv(struct stm32_spi *spi) } /** - * stm32_spi_write_txfifo - Write bytes in Transmit Data Register + * stm32h7_spi_write_txfifo - Write bytes in Transmit Data Register * @spi: pointer to the spi controller data structure * * Read from tx_buf depends on remaining bytes to avoid to read beyond * tx_buf end. */ -static void stm32_spi_write_txfifo(struct stm32_spi *spi) +static void stm32h7_spi_write_txfifo(struct stm32_spi *spi) { while ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32H7_SPI_SR) & @@ -338,13 +444,13 @@ static void stm32_spi_write_txfifo(struct stm32_spi *spi) } /** - * stm32_spi_read_rxfifo - Read bytes in Receive Data Register + * stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register * @spi: pointer to the spi controller data structure * * Write in rx_buf depends on remaining bytes to avoid to write beyond * rx_buf end. */ -static void stm32_spi_read_rxfifo(struct stm32_spi *spi, bool flush) +static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) { u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR); u32 rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> @@ -386,26 +492,28 @@ static void stm32_spi_read_rxfifo(struct stm32_spi *spi, bool flush) /** * stm32_spi_enable - Enable SPI controller * @spi: pointer to the spi controller data structure - * - * SPI data transfer is enabled but spi_ker_ck is idle. - * SPI_CFG1 and SPI_CFG2 are now write protected. */ static void stm32_spi_enable(struct stm32_spi *spi) { dev_dbg(spi->dev, "enable controller\n"); - stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE); + stm32_spi_set_bits(spi, spi->cfg->regs->en.reg, + spi->cfg->regs->en.mask); } /** - * stm32_spi_disable - Disable SPI controller + * stm32h7_spi_disable - Disable SPI controller * @spi: pointer to the spi controller data structure * * RX-Fifo is flushed when SPI controller is disabled. To prevent any data - * loss, use stm32_spi_read_rxfifo(flush) to read the remaining bytes in + * loss, use stm32h7_spi_read_rxfifo(flush) to read the remaining bytes in * RX-Fifo. + * Normally, if TSIZE has been configured, we should relax the hardware at the + * reception of the EOT interrupt. But in case of error, EOT will not be + * raised. So the subsystem unprepare_message call allows us to properly + * complete the transfer from an hardware point of view. */ -static void stm32_spi_disable(struct stm32_spi *spi) +static void stm32h7_spi_disable(struct stm32_spi *spi) { unsigned long flags; u32 cr1, sr; @@ -438,7 +546,7 @@ static void stm32_spi_disable(struct stm32_spi *spi) } if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) - stm32_spi_read_rxfifo(spi, true); + stm32h7_spi_read_rxfifo(spi, true); if (spi->cur_usedma && spi->dma_tx) dmaengine_terminate_all(spi->dma_tx); @@ -475,11 +583,11 @@ static bool stm32_spi_can_dma(struct spi_master *master, } /** - * stm32_spi_irq_thread - Thread of interrupt handler for SPI controller + * stm32h7_spi_irq_thread - Thread of interrupt handler for SPI controller * @irq: interrupt line * @dev_id: SPI controller master interface */ -static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id) +static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) { struct spi_master *master = dev_id; struct stm32_spi *spi = spi_master_get_devdata(master); @@ -513,7 +621,7 @@ static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id) if (sr & STM32H7_SPI_SR_SUSP) { dev_warn(spi->dev, "Communication suspended\n"); if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) - stm32_spi_read_rxfifo(spi, false); + stm32h7_spi_read_rxfifo(spi, false); /* * If communication is suspended while using DMA, it means * that something went wrong, so stop the current transfer @@ -530,7 +638,7 @@ static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id) if (sr & STM32H7_SPI_SR_OVR) { dev_warn(spi->dev, "Overrun: received value discarded\n"); if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) - stm32_spi_read_rxfifo(spi, false); + stm32h7_spi_read_rxfifo(spi, false); /* * If overrun is detected while using DMA, it means that * something went wrong, so stop the current transfer @@ -541,17 +649,17 @@ static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id) if (sr & STM32H7_SPI_SR_EOT) { if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) - stm32_spi_read_rxfifo(spi, true); + stm32h7_spi_read_rxfifo(spi, true); end = true; } if (sr & STM32H7_SPI_SR_TXP) if (!spi->cur_usedma && (spi->tx_buf && (spi->tx_len > 0))) - stm32_spi_write_txfifo(spi); + stm32h7_spi_write_txfifo(spi); if (sr & STM32H7_SPI_SR_RXP) if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) - stm32_spi_read_rxfifo(spi, false); + stm32h7_spi_read_rxfifo(spi, false); writel_relaxed(mask, spi->base + STM32H7_SPI_IFCR); @@ -559,7 +667,7 @@ static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id) if (end) { spi_finalize_current_transfer(master); - stm32_spi_disable(spi); + stm32h7_spi_disable(spi); } return IRQ_HANDLED; @@ -598,7 +706,7 @@ static int stm32_spi_prepare_msg(struct spi_master *master, struct spi_device *spi_dev = msg->spi; struct device_node *np = spi_dev->dev.of_node; unsigned long flags; - u32 cfg2_clrb = 0, cfg2_setb = 0; + u32 clrb = 0, setb = 0; /* SPI slave device may need time between data frames */ spi->cur_midi = 0; @@ -606,19 +714,19 @@ static int stm32_spi_prepare_msg(struct spi_master *master, dev_dbg(spi->dev, "%dns inter-data idleness\n", spi->cur_midi); if (spi_dev->mode & SPI_CPOL) - cfg2_setb |= STM32H7_SPI_CFG2_CPOL; + setb |= spi->cfg->regs->cpol.mask; else - cfg2_clrb |= STM32H7_SPI_CFG2_CPOL; + clrb |= spi->cfg->regs->cpol.mask; if (spi_dev->mode & SPI_CPHA) - cfg2_setb |= STM32H7_SPI_CFG2_CPHA; + setb |= spi->cfg->regs->cpha.mask; else - cfg2_clrb |= STM32H7_SPI_CFG2_CPHA; + clrb |= spi->cfg->regs->cpha.mask; if (spi_dev->mode & SPI_LSB_FIRST) - cfg2_setb |= STM32H7_SPI_CFG2_LSBFRST; + setb |= spi->cfg->regs->lsb_first.mask; else - cfg2_clrb |= STM32H7_SPI_CFG2_LSBFRST; + clrb |= spi->cfg->regs->lsb_first.mask; dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d\n", spi_dev->mode & SPI_CPOL, @@ -628,11 +736,12 @@ static int stm32_spi_prepare_msg(struct spi_master *master, spin_lock_irqsave(&spi->lock, flags); - if (cfg2_clrb || cfg2_setb) + /* CPOL, CPHA and LSB FIRST bits have common register */ + if (clrb || setb) writel_relaxed( - (readl_relaxed(spi->base + STM32H7_SPI_CFG2) & - ~cfg2_clrb) | cfg2_setb, - spi->base + STM32H7_SPI_CFG2); + (readl_relaxed(spi->base + spi->cfg->regs->cpol.reg) & + ~clrb) | setb, + spi->base + spi->cfg->regs->cpol.reg); spin_unlock_irqrestore(&spi->lock, flags); @@ -640,12 +749,12 @@ static int stm32_spi_prepare_msg(struct spi_master *master, } /** - * stm32_spi_dma_cb - dma callback + * stm32h7_spi_dma_cb - dma callback * * DMA callback is called when the transfer is complete or when an error * occurs. If the transfer is complete, EOT flag is raised. */ -static void stm32_spi_dma_cb(void *data) +static void stm32h7_spi_dma_cb(void *data) { struct stm32_spi *spi = data; unsigned long flags; @@ -690,14 +799,14 @@ static void stm32_spi_dma_config(struct stm32_spi *spi, memset(dma_conf, 0, sizeof(struct dma_slave_config)); dma_conf->direction = dir; if (dma_conf->direction == DMA_DEV_TO_MEM) { /* RX */ - dma_conf->src_addr = spi->phys_addr + STM32H7_SPI_RXDR; + dma_conf->src_addr = spi->phys_addr + spi->cfg->regs->rx.reg; dma_conf->src_addr_width = buswidth; dma_conf->src_maxburst = maxburst; dev_dbg(spi->dev, "Rx DMA config buswidth=%d, maxburst=%d\n", buswidth, maxburst); } else if (dma_conf->direction == DMA_MEM_TO_DEV) { /* TX */ - dma_conf->dst_addr = spi->phys_addr + STM32H7_SPI_TXDR; + dma_conf->dst_addr = spi->phys_addr + spi->cfg->regs->tx.reg; dma_conf->dst_addr_width = buswidth; dma_conf->dst_maxburst = maxburst; @@ -707,13 +816,13 @@ static void stm32_spi_dma_config(struct stm32_spi *spi, } /** - * stm32_spi_transfer_one_irq - transfer a single spi_transfer using - * interrupts + * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using + * interrupts * * It must returns 0 if the transfer is finished or 1 if the transfer is still * in progress. */ -static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) +static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) { unsigned long flags; u32 ier = 0; @@ -736,7 +845,7 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) /* Be sure to have data in fifo before starting data transfer */ if (spi->tx_buf) - stm32_spi_write_txfifo(spi); + stm32h7_spi_write_txfifo(spi); stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); @@ -748,10 +857,10 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) } /** - * stm32_spi_transfer_one_dma_start - Set SPI driver registers to start transfer - * using DMA + * stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start + * transfer using DMA */ -static void stm32_spi_transfer_one_dma_start(struct stm32_spi *spi) +static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) { /* Enable the interrupts relative to the end of transfer */ stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE | @@ -785,8 +894,8 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, dmaengine_slave_config(spi->dma_rx, &rx_dma_conf); /* Enable Rx DMA request */ - stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, - STM32H7_SPI_CFG1_RXDMAEN); + stm32_spi_set_bits(spi, spi->cfg->regs->dma_rx_en.reg, + spi->cfg->regs->dma_rx_en.mask); rx_dma_desc = dmaengine_prep_slave_sg( spi->dma_rx, xfer->rx_sg.sgl, @@ -815,7 +924,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, goto dma_desc_error; if (rx_dma_desc) { - rx_dma_desc->callback = stm32_spi_dma_cb; + rx_dma_desc->callback = spi->cfg->dma_rx_cb; rx_dma_desc->callback_param = spi; if (dma_submit_error(dmaengine_submit(rx_dma_desc))) { @@ -829,7 +938,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, if (tx_dma_desc) { if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) { - tx_dma_desc->callback = stm32_spi_dma_cb; + tx_dma_desc->callback = spi->cfg->dma_tx_cb; tx_dma_desc->callback_param = spi; } @@ -841,11 +950,11 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, dma_async_issue_pending(spi->dma_tx); /* Enable Tx DMA request */ - stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, - STM32H7_SPI_CFG1_TXDMAEN); + stm32_spi_set_bits(spi, spi->cfg->regs->dma_tx_en.reg, + spi->cfg->regs->dma_tx_en.mask); } - stm32_spi_transfer_one_dma_start(spi); + spi->cfg->transfer_one_dma_start(spi); spin_unlock_irqrestore(&spi->lock, flags); @@ -856,21 +965,22 @@ dma_submit_error: dmaengine_terminate_all(spi->dma_rx); dma_desc_error: - stm32_spi_clr_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_RXDMAEN); + stm32_spi_clr_bits(spi, spi->cfg->regs->dma_rx_en.reg, + spi->cfg->regs->dma_rx_en.mask); spin_unlock_irqrestore(&spi->lock, flags); dev_info(spi->dev, "DMA issue: fall back to irq transfer\n"); spi->cur_usedma = false; - return stm32_spi_transfer_one_irq(spi); + return spi->cfg->transfer_one_irq(spi); } /** - * stm32_spi_set_bpw - configure bits per word + * stm32h7_spi_set_bpw - configure bits per word * @spi: pointer to the spi controller data structure */ -static void stm32_spi_set_bpw(struct stm32_spi *spi) +static void stm32h7_spi_set_bpw(struct stm32_spi *spi) { u32 bpw, fthlv; u32 cfg1_clrb = 0, cfg1_setb = 0; @@ -881,7 +991,7 @@ static void stm32_spi_set_bpw(struct stm32_spi *spi) cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & STM32H7_SPI_CFG1_DSIZE; - spi->cur_fthlv = stm32_spi_prepare_fthlv(spi); + spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi); fthlv = spi->cur_fthlv - 1; cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; @@ -901,15 +1011,15 @@ static void stm32_spi_set_bpw(struct stm32_spi *spi) */ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) { - u32 cfg1_clrb = 0, cfg1_setb = 0; + u32 clrb = 0, setb = 0; - cfg1_clrb |= STM32H7_SPI_CFG1_MBR; - cfg1_setb |= ((u32)mbrdiv << STM32H7_SPI_CFG1_MBR_SHIFT) & - STM32H7_SPI_CFG1_MBR; + clrb |= spi->cfg->regs->br.mask; + setb |= ((u32)mbrdiv << spi->cfg->regs->br.shift) & + spi->cfg->regs->br.mask; - writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG1) & - ~cfg1_clrb) | cfg1_setb, - spi->base + STM32H7_SPI_CFG1); + writel_relaxed((readl_relaxed(spi->base + spi->cfg->regs->br.reg) & + ~clrb) | setb, + spi->base + spi->cfg->regs->br.reg); } /** @@ -944,11 +1054,11 @@ static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev, } /** - * stm32_spi_set_mode - configure communication mode + * stm32h7_spi_set_mode - configure communication mode * @spi: pointer to the spi controller data structure * @comm_type: type of communication to configure */ -static int stm32_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) +static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) { u32 mode; u32 cfg2_clrb = 0, cfg2_setb = 0; @@ -980,12 +1090,12 @@ static int stm32_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) } /** - * stm32_spi_data_idleness - configure minimum time delay inserted between two - * consecutive data frames in master mode + * stm32h7_spi_data_idleness - configure minimum time delay inserted between two + * consecutive data frames in master mode * @spi: pointer to the spi controller data structure * @len: transfer len */ -static void stm32_spi_data_idleness(struct stm32_spi *spi, u32 len) +static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) { u32 cfg2_clrb = 0, cfg2_setb = 0; @@ -1008,11 +1118,11 @@ static void stm32_spi_data_idleness(struct stm32_spi *spi, u32 len) } /** - * stm32_spi_number_of_data - configure number of data at current transfer + * stm32h7_spi_number_of_data - configure number of data at current transfer * @spi: pointer to the spi controller data structure * @len: transfer length */ -static int stm32_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) +static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) { u32 cr2_clrb = 0, cr2_setb = 0; @@ -1047,7 +1157,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, if (spi->cur_bpw != transfer->bits_per_word) { spi->cur_bpw = transfer->bits_per_word; - stm32_spi_set_bpw(spi); + spi->cfg->set_bpw(spi); } if (spi->cur_speed != transfer->speed_hz) { @@ -1055,8 +1165,8 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, /* Update spi->cur_speed with real clock speed */ mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, - STM32H7_SPI_MBR_DIV_MIN, - STM32H7_SPI_MBR_DIV_MAX); + spi->cfg->baud_rate_div_min, + spi->cfg->baud_rate_div_max); if (mbr < 0) { ret = mbr; goto out; @@ -1068,7 +1178,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, comm_type = stm32_spi_communication_type(spi_dev, transfer); if (spi->cur_comm != comm_type) { - stm32_spi_set_mode(spi, comm_type); + ret = spi->cfg->set_mode(spi, comm_type); if (ret < 0) goto out; @@ -1076,7 +1186,8 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, spi->cur_comm = comm_type; } - stm32_spi_data_idleness(spi, transfer->len); + if (spi->cfg->set_data_idleness) + spi->cfg->set_data_idleness(spi, transfer->len); if (spi->cur_bpw <= 8) nb_words = transfer->len; @@ -1085,9 +1196,11 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, else nb_words = DIV_ROUND_UP(transfer->len * 8, 32); - ret = stm32_spi_number_of_data(spi, nb_words); - if (ret < 0) - goto out; + if (spi->cfg->set_number_of_data) { + ret = spi->cfg->set_number_of_data(spi, nb_words); + if (ret < 0) + goto out; + } spi->cur_xferlen = transfer->len; @@ -1138,31 +1251,26 @@ static int stm32_spi_transfer_one(struct spi_master *master, if (spi->cur_usedma) return stm32_spi_transfer_one_dma(spi, transfer); else - return stm32_spi_transfer_one_irq(spi); + return spi->cfg->transfer_one_irq(spi); } /** * stm32_spi_unprepare_msg - relax the hardware - * - * Normally, if TSIZE has been configured, we should relax the hardware at the - * reception of the EOT interrupt. But in case of error, EOT will not be - * raised. So the subsystem unprepare_message call allows us to properly - * complete the transfer from an hardware point of view. */ static int stm32_spi_unprepare_msg(struct spi_master *master, struct spi_message *msg) { struct stm32_spi *spi = spi_master_get_devdata(master); - stm32_spi_disable(spi); + spi->cfg->disable(spi); return 0; } /** - * stm32_spi_config - Configure SPI controller as SPI master + * stm32h7_spi_config - Configure SPI controller as SPI master */ -static int stm32_spi_config(struct stm32_spi *spi) +static int stm32h7_spi_config(struct stm32_spi *spi) { unsigned long flags; @@ -1196,8 +1304,28 @@ static int stm32_spi_config(struct stm32_spi *spi) return 0; } +static const struct stm32_spi_cfg stm32h7_spi_cfg = { + .regs = &stm32h7_spi_regspec, + .get_fifo_size = stm32h7_spi_get_fifo_size, + .get_bpw_mask = stm32h7_spi_get_bpw_mask, + .disable = stm32h7_spi_disable, + .config = stm32h7_spi_config, + .set_bpw = stm32h7_spi_set_bpw, + .set_mode = stm32h7_spi_set_mode, + .set_data_idleness = stm32h7_spi_data_idleness, + .set_number_of_data = stm32h7_spi_number_of_data, + .transfer_one_dma_start = stm32h7_spi_transfer_one_dma_start, + .dma_rx_cb = stm32h7_spi_dma_cb, + .dma_tx_cb = stm32h7_spi_dma_cb, + .transfer_one_irq = stm32h7_spi_transfer_one_irq, + .irq_handler_thread = stm32h7_spi_irq_thread, + .baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN, + .baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX, + .has_fifo = true, +}; + static const struct of_device_id stm32_spi_of_match[] = { - { .compatible = "st,stm32h7-spi", }, + { .compatible = "st,stm32h7-spi", .data = (void *)&stm32h7_spi_cfg }, {}, }; MODULE_DEVICE_TABLE(of, stm32_spi_of_match); @@ -1221,12 +1349,17 @@ static int stm32_spi_probe(struct platform_device *pdev) spi->master = master; spin_lock_init(&spi->lock); + spi->cfg = (const struct stm32_spi_cfg *) + of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev)->data; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spi->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(spi->base)) { ret = PTR_ERR(spi->base); goto err_master_put; } + spi->phys_addr = (dma_addr_t)res->start; spi->irq = platform_get_irq(pdev, 0); @@ -1235,9 +1368,10 @@ static int stm32_spi_probe(struct platform_device *pdev) ret = -ENOENT; goto err_master_put; } - ret = devm_request_threaded_irq(&pdev->dev, spi->irq, NULL, - stm32_spi_irq_thread, IRQF_ONESHOT, - pdev->name, master); + ret = devm_request_threaded_irq(&pdev->dev, spi->irq, + spi->cfg->irq_handler_event, + spi->cfg->irq_handler_thread, + IRQF_ONESHOT, pdev->name, master); if (ret) { dev_err(&pdev->dev, "irq%d request failed: %d\n", spi->irq, ret); @@ -1270,9 +1404,10 @@ static int stm32_spi_probe(struct platform_device *pdev) reset_control_deassert(spi->rst); } - spi->fifo_size = stm32_spi_get_fifo_size(spi); + if (spi->cfg->has_fifo) + spi->fifo_size = spi->cfg->get_fifo_size(spi); - ret = stm32_spi_config(spi); + ret = spi->cfg->config(spi); if (ret) { dev_err(&pdev->dev, "controller configuration failed: %d\n", ret); @@ -1284,9 +1419,9 @@ static int stm32_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE; - master->bits_per_word_mask = stm32_spi_get_bpw_mask(spi); - master->max_speed_hz = spi->clk_rate / STM32H7_SPI_MBR_DIV_MIN; - master->min_speed_hz = spi->clk_rate / STM32H7_SPI_MBR_DIV_MAX; + master->bits_per_word_mask = spi->cfg->get_bpw_mask(spi); + master->max_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_min; + master->min_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_max; master->setup = stm32_spi_setup; master->prepare_message = stm32_spi_prepare_msg; master->transfer_one = stm32_spi_transfer_one; @@ -1364,7 +1499,7 @@ static int stm32_spi_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct stm32_spi *spi = spi_master_get_devdata(master); - stm32_spi_disable(spi); + spi->cfg->disable(spi); if (master->dma_tx) dma_release_channel(master->dma_tx); -- cgit v1.2.3 From 00505edf95115707d91afd2685993b98daa93f15 Mon Sep 17 00:00:00 2001 From: Cezary Gapinski Date: Mon, 24 Dec 2018 23:00:38 +0100 Subject: spi: stm32: add support for STM32F4 Add routines, registers & bitfield definition. Also baud rate divisor definitions for STM32F4 SPI. This version supports full-duplex, simplex TX and half-duplex TX communication with 8 or 16-bit per word. DMA capability is optionally supported for transfer longer than 16 bytes. For transfer less than 16 bytes frames can be send in discontinuous mode. Signed-off-by: Cezary Gapinski Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 489 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 482 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 8b10074cc75f..4186ed20d796 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -20,6 +20,59 @@ #define DRIVER_NAME "spi_stm32" +/* STM32F4 SPI registers */ +#define STM32F4_SPI_CR1 0x00 +#define STM32F4_SPI_CR2 0x04 +#define STM32F4_SPI_SR 0x08 +#define STM32F4_SPI_DR 0x0C +#define STM32F4_SPI_I2SCFGR 0x1C + +/* STM32F4_SPI_CR1 bit fields */ +#define STM32F4_SPI_CR1_CPHA BIT(0) +#define STM32F4_SPI_CR1_CPOL BIT(1) +#define STM32F4_SPI_CR1_MSTR BIT(2) +#define STM32F4_SPI_CR1_BR_SHIFT 3 +#define STM32F4_SPI_CR1_BR GENMASK(5, 3) +#define STM32F4_SPI_CR1_SPE BIT(6) +#define STM32F4_SPI_CR1_LSBFRST BIT(7) +#define STM32F4_SPI_CR1_SSI BIT(8) +#define STM32F4_SPI_CR1_SSM BIT(9) +#define STM32F4_SPI_CR1_RXONLY BIT(10) +#define STM32F4_SPI_CR1_DFF BIT(11) +#define STM32F4_SPI_CR1_CRCNEXT BIT(12) +#define STM32F4_SPI_CR1_CRCEN BIT(13) +#define STM32F4_SPI_CR1_BIDIOE BIT(14) +#define STM32F4_SPI_CR1_BIDIMODE BIT(15) +#define STM32F4_SPI_CR1_BR_MIN 0 +#define STM32F4_SPI_CR1_BR_MAX (GENMASK(5, 3) >> 3) + +/* STM32F4_SPI_CR2 bit fields */ +#define STM32F4_SPI_CR2_RXDMAEN BIT(0) +#define STM32F4_SPI_CR2_TXDMAEN BIT(1) +#define STM32F4_SPI_CR2_SSOE BIT(2) +#define STM32F4_SPI_CR2_FRF BIT(4) +#define STM32F4_SPI_CR2_ERRIE BIT(5) +#define STM32F4_SPI_CR2_RXNEIE BIT(6) +#define STM32F4_SPI_CR2_TXEIE BIT(7) + +/* STM32F4_SPI_SR bit fields */ +#define STM32F4_SPI_SR_RXNE BIT(0) +#define STM32F4_SPI_SR_TXE BIT(1) +#define STM32F4_SPI_SR_CHSIDE BIT(2) +#define STM32F4_SPI_SR_UDR BIT(3) +#define STM32F4_SPI_SR_CRCERR BIT(4) +#define STM32F4_SPI_SR_MODF BIT(5) +#define STM32F4_SPI_SR_OVR BIT(6) +#define STM32F4_SPI_SR_BSY BIT(7) +#define STM32F4_SPI_SR_FRE BIT(8) + +/* STM32F4_SPI_I2SCFGR bit fields */ +#define STM32F4_SPI_I2SCFGR_I2SMOD BIT(11) + +/* STM32F4 SPI Baud Rate min/max divisor */ +#define STM32F4_SPI_BR_DIV_MIN (2 << STM32F4_SPI_CR1_BR_MIN) +#define STM32F4_SPI_BR_DIV_MAX (2 << STM32F4_SPI_CR1_BR_MAX) + /* STM32H7 SPI registers */ #define STM32H7_SPI_CR1 0x00 #define STM32H7_SPI_CR2 0x04 @@ -116,6 +169,12 @@ #define SPI_1HZ_NS 1000000000 +/* + * use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers + * without fifo buffers. + */ +#define SPI_DMA_MIN_BYTES 16 + /** * stm32_spi_reg - stm32 SPI register & bitfield desc * @reg: register offset @@ -257,6 +316,21 @@ struct stm32_spi { dma_addr_t phys_addr; }; +static const struct stm32_spi_regspec stm32f4_spi_regspec = { + .en = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE }, + + .dma_rx_en = { STM32F4_SPI_CR2, STM32F4_SPI_CR2_RXDMAEN }, + .dma_tx_en = { STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXDMAEN }, + + .cpol = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPOL }, + .cpha = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPHA }, + .lsb_first = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_LSBFRST }, + .br = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_BR, STM32F4_SPI_CR1_BR_SHIFT }, + + .rx = { STM32F4_SPI_DR }, + .tx = { STM32F4_SPI_DR }, +}; + static const struct stm32_spi_regspec stm32h7_spi_regspec = { /* SPI data transfer is enabled but spi_ker_ck is idle. * CFG1 and CFG2 registers are write protected when SPE is enabled. @@ -315,6 +389,16 @@ static int stm32h7_spi_get_fifo_size(struct stm32_spi *spi) return count; } +/** + * stm32f4_spi_get_bpw_mask - Return bits per word mask + * @spi: pointer to the spi controller data structure + */ +static int stm32f4_spi_get_bpw_mask(struct stm32_spi *spi) +{ + dev_dbg(spi->dev, "8-bit or 16-bit data frame supported\n"); + return SPI_BPW_MASK(8) | SPI_BPW_MASK(16); +} + /** * stm32h7_spi_get_bpw_mask - Return bits per word mask * @spi: pointer to the spi controller data structure @@ -408,6 +492,35 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) return fthlv; } +/** + * stm32f4_spi_write_tx - Write bytes to Transmit Data Register + * @spi: pointer to the spi controller data structure + * + * Read from tx_buf depends on remaining bytes to avoid to read beyond + * tx_buf end. + */ +static void stm32f4_spi_write_tx(struct stm32_spi *spi) +{ + if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32F4_SPI_SR) & + STM32F4_SPI_SR_TXE)) { + u32 offs = spi->cur_xferlen - spi->tx_len; + + if (spi->cur_bpw == 16) { + const u16 *tx_buf16 = (const u16 *)(spi->tx_buf + offs); + + writew_relaxed(*tx_buf16, spi->base + STM32F4_SPI_DR); + spi->tx_len -= sizeof(u16); + } else { + const u8 *tx_buf8 = (const u8 *)(spi->tx_buf + offs); + + writeb_relaxed(*tx_buf8, spi->base + STM32F4_SPI_DR); + spi->tx_len -= sizeof(u8); + } + } + + dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len); +} + /** * stm32h7_spi_write_txfifo - Write bytes in Transmit Data Register * @spi: pointer to the spi controller data structure @@ -443,6 +556,35 @@ static void stm32h7_spi_write_txfifo(struct stm32_spi *spi) dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len); } +/** + * stm32f4_spi_read_rx - Read bytes from Receive Data Register + * @spi: pointer to the spi controller data structure + * + * Write in rx_buf depends on remaining bytes to avoid to write beyond + * rx_buf end. + */ +static void stm32f4_spi_read_rx(struct stm32_spi *spi) +{ + if ((spi->rx_len > 0) && (readl_relaxed(spi->base + STM32F4_SPI_SR) & + STM32F4_SPI_SR_RXNE)) { + u32 offs = spi->cur_xferlen - spi->rx_len; + + if (spi->cur_bpw == 16) { + u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); + + *rx_buf16 = readw_relaxed(spi->base + STM32F4_SPI_DR); + spi->rx_len -= sizeof(u16); + } else { + u8 *rx_buf8 = (u8 *)(spi->rx_buf + offs); + + *rx_buf8 = readb_relaxed(spi->base + STM32F4_SPI_DR); + spi->rx_len -= sizeof(u8); + } + } + + dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->rx_len); +} + /** * stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register * @spi: pointer to the spi controller data structure @@ -501,6 +643,54 @@ static void stm32_spi_enable(struct stm32_spi *spi) spi->cfg->regs->en.mask); } +/** + * stm32f4_spi_disable - Disable SPI controller + * @spi: pointer to the spi controller data structure + */ +static void stm32f4_spi_disable(struct stm32_spi *spi) +{ + unsigned long flags; + u32 sr; + + dev_dbg(spi->dev, "disable controller\n"); + + spin_lock_irqsave(&spi->lock, flags); + + if (!(readl_relaxed(spi->base + STM32F4_SPI_CR1) & + STM32F4_SPI_CR1_SPE)) { + spin_unlock_irqrestore(&spi->lock, flags); + return; + } + + /* Disable interrupts */ + stm32_spi_clr_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXEIE | + STM32F4_SPI_CR2_RXNEIE | + STM32F4_SPI_CR2_ERRIE); + + /* Wait until BSY = 0 */ + if (readl_relaxed_poll_timeout_atomic(spi->base + STM32F4_SPI_SR, + sr, !(sr & STM32F4_SPI_SR_BSY), + 10, 100000) < 0) { + dev_warn(spi->dev, "disabling condition timeout\n"); + } + + if (spi->cur_usedma && spi->dma_tx) + dmaengine_terminate_all(spi->dma_tx); + if (spi->cur_usedma && spi->dma_rx) + dmaengine_terminate_all(spi->dma_rx); + + stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE); + + stm32_spi_clr_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXDMAEN | + STM32F4_SPI_CR2_RXDMAEN); + + /* Sequence to clear OVR flag */ + readl_relaxed(spi->base + STM32F4_SPI_DR); + readl_relaxed(spi->base + STM32F4_SPI_SR); + + spin_unlock_irqrestore(&spi->lock, flags); +} + /** * stm32h7_spi_disable - Disable SPI controller * @spi: pointer to the spi controller data structure @@ -568,18 +758,128 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) /** * stm32_spi_can_dma - Determine if the transfer is eligible for DMA use * - * If the current transfer size is greater than fifo size, use DMA. + * If driver has fifo and the current transfer size is greater than fifo size, + * use DMA. Otherwise use DMA for transfer longer than defined DMA min bytes. */ static bool stm32_spi_can_dma(struct spi_master *master, struct spi_device *spi_dev, struct spi_transfer *transfer) { + unsigned int dma_size; struct stm32_spi *spi = spi_master_get_devdata(master); + if (spi->cfg->has_fifo) + dma_size = spi->fifo_size; + else + dma_size = SPI_DMA_MIN_BYTES; + dev_dbg(spi->dev, "%s: %s\n", __func__, - (transfer->len > spi->fifo_size) ? "true" : "false"); + (transfer->len > dma_size) ? "true" : "false"); + + return (transfer->len > dma_size); +} + +/** + * stm32f4_spi_irq_event - Interrupt handler for SPI controller events + * @irq: interrupt line + * @dev_id: SPI controller master interface + */ +static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id) +{ + struct spi_master *master = dev_id; + struct stm32_spi *spi = spi_master_get_devdata(master); + u32 sr, mask = 0; + unsigned long flags; + bool end = false; + + spin_lock_irqsave(&spi->lock, flags); + + sr = readl_relaxed(spi->base + STM32F4_SPI_SR); + /* + * BSY flag is not handled in interrupt but it is normal behavior when + * this flag is set. + */ + sr &= ~STM32F4_SPI_SR_BSY; + + if (!spi->cur_usedma && (spi->cur_comm == SPI_SIMPLEX_TX || + spi->cur_comm == SPI_3WIRE_TX)) { + /* OVR flag shouldn't be handled for TX only mode */ + sr &= ~STM32F4_SPI_SR_OVR | STM32F4_SPI_SR_RXNE; + mask |= STM32F4_SPI_SR_TXE; + } + + if (!spi->cur_usedma && spi->cur_comm == SPI_FULL_DUPLEX) { + /* TXE flag is set and is handled when RXNE flag occurs */ + sr &= ~STM32F4_SPI_SR_TXE; + mask |= STM32F4_SPI_SR_RXNE | STM32F4_SPI_SR_OVR; + } + + if (!(sr & mask)) { + dev_dbg(spi->dev, "spurious IT (sr=0x%08x)\n", sr); + spin_unlock_irqrestore(&spi->lock, flags); + return IRQ_NONE; + } + + if (sr & STM32F4_SPI_SR_OVR) { + dev_warn(spi->dev, "Overrun: received value discarded\n"); + + /* Sequence to clear OVR flag */ + readl_relaxed(spi->base + STM32F4_SPI_DR); + readl_relaxed(spi->base + STM32F4_SPI_SR); + + /* + * If overrun is detected, it means that something went wrong, + * so stop the current transfer. Transfer can wait for next + * RXNE but DR is already read and end never happens. + */ + end = true; + goto end_irq; + } + + if (sr & STM32F4_SPI_SR_TXE) { + if (spi->tx_buf) + stm32f4_spi_write_tx(spi); + if (spi->tx_len == 0) + end = true; + } + + if (sr & STM32F4_SPI_SR_RXNE) { + stm32f4_spi_read_rx(spi); + if (spi->rx_len == 0) + end = true; + else /* Load data for discontinuous mode */ + stm32f4_spi_write_tx(spi); + } + +end_irq: + if (end) { + /* Immediately disable interrupts to do not generate new one */ + stm32_spi_clr_bits(spi, STM32F4_SPI_CR2, + STM32F4_SPI_CR2_TXEIE | + STM32F4_SPI_CR2_RXNEIE | + STM32F4_SPI_CR2_ERRIE); + spin_unlock_irqrestore(&spi->lock, flags); + return IRQ_WAKE_THREAD; + } + + spin_unlock_irqrestore(&spi->lock, flags); + return IRQ_HANDLED; +} + +/** + * stm32f4_spi_irq_thread - Thread of interrupt handler for SPI controller + * @irq: interrupt line + * @dev_id: SPI controller master interface + */ +static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id) +{ + struct spi_master *master = dev_id; + struct stm32_spi *spi = spi_master_get_devdata(master); + + spi_finalize_current_transfer(master); + stm32f4_spi_disable(spi); - return (transfer->len > spi->fifo_size); + return IRQ_HANDLED; } /** @@ -748,6 +1048,34 @@ static int stm32_spi_prepare_msg(struct spi_master *master, return 0; } +/** + * stm32f4_spi_dma_tx_cb - dma callback + * + * DMA callback is called when the transfer is complete for DMA TX channel. + */ +static void stm32f4_spi_dma_tx_cb(void *data) +{ + struct stm32_spi *spi = data; + + if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) { + spi_finalize_current_transfer(spi->master); + stm32f4_spi_disable(spi); + } +} + +/** + * stm32f4_spi_dma_rx_cb - dma callback + * + * DMA callback is called when the transfer is complete for DMA RX channel. + */ +static void stm32f4_spi_dma_rx_cb(void *data) +{ + struct stm32_spi *spi = data; + + spi_finalize_current_transfer(spi->master); + stm32f4_spi_disable(spi); +} + /** * stm32h7_spi_dma_cb - dma callback * @@ -790,11 +1118,15 @@ static void stm32_spi_dma_config(struct stm32_spi *spi, else buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; - /* Valid for DMA Half or Full Fifo threshold */ - if (spi->cur_fthlv == 2) + if (spi->cfg->has_fifo) { + /* Valid for DMA Half or Full Fifo threshold */ + if (spi->cur_fthlv == 2) + maxburst = 1; + else + maxburst = spi->cur_fthlv; + } else { maxburst = 1; - else - maxburst = spi->cur_fthlv; + } memset(dma_conf, 0, sizeof(struct dma_slave_config)); dma_conf->direction = dir; @@ -815,6 +1147,46 @@ static void stm32_spi_dma_config(struct stm32_spi *spi, } } +/** + * stm32f4_spi_transfer_one_irq - transfer a single spi_transfer using + * interrupts + * + * It must returns 0 if the transfer is finished or 1 if the transfer is still + * in progress. + */ +static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi) +{ + unsigned long flags; + u32 cr2 = 0; + + /* Enable the interrupts relative to the current communication mode */ + if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) { + cr2 |= STM32F4_SPI_CR2_TXEIE; + } else if (spi->cur_comm == SPI_FULL_DUPLEX) { + /* In transmit-only mode, the OVR flag is set in the SR register + * since the received data are never read. Therefore set OVR + * interrupt only when rx buffer is available. + */ + cr2 |= STM32F4_SPI_CR2_RXNEIE | STM32F4_SPI_CR2_ERRIE; + } else { + return -EINVAL; + } + + spin_lock_irqsave(&spi->lock, flags); + + stm32_spi_set_bits(spi, STM32F4_SPI_CR2, cr2); + + stm32_spi_enable(spi); + + /* starting data transfer when buffer is loaded */ + if (spi->tx_buf) + stm32f4_spi_write_tx(spi); + + spin_unlock_irqrestore(&spi->lock, flags); + + return 1; +} + /** * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using * interrupts @@ -856,6 +1228,26 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) return 1; } +/** + * stm32f4_spi_transfer_one_dma_start - Set SPI driver registers to start + * transfer using DMA + */ +static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) +{ + /* In DMA mode end of transfer is handled by DMA TX or RX callback. */ + if (spi->cur_comm == SPI_SIMPLEX_RX || spi->cur_comm == SPI_3WIRE_RX || + spi->cur_comm == SPI_FULL_DUPLEX) { + /* + * In transmit-only mode, the OVR flag is set in the SR register + * since the received data are never read. Therefore set OVR + * interrupt only when rx buffer is available. + */ + stm32_spi_set_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_ERRIE); + } + + stm32_spi_enable(spi); +} + /** * stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start * transfer using DMA @@ -976,6 +1368,18 @@ dma_desc_error: return spi->cfg->transfer_one_irq(spi); } +/** + * stm32f4_spi_set_bpw - Configure bits per word + * @spi: pointer to the spi controller data structure + */ +static void stm32f4_spi_set_bpw(struct stm32_spi *spi) +{ + if (spi->cur_bpw == 16) + stm32_spi_set_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_DFF); + else + stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_DFF); +} + /** * stm32h7_spi_set_bpw - configure bits per word * @spi: pointer to the spi controller data structure @@ -1053,6 +1457,28 @@ static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev, return type; } +/** + * stm32f4_spi_set_mode - configure communication mode + * @spi: pointer to the spi controller data structure + * @comm_type: type of communication to configure + */ +static int stm32f4_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) +{ + if (comm_type == SPI_3WIRE_TX || comm_type == SPI_SIMPLEX_TX) { + stm32_spi_set_bits(spi, STM32F4_SPI_CR1, + STM32F4_SPI_CR1_BIDIMODE | + STM32F4_SPI_CR1_BIDIOE); + } else if (comm_type == SPI_FULL_DUPLEX) { + stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, + STM32F4_SPI_CR1_BIDIMODE | + STM32F4_SPI_CR1_BIDIOE); + } else { + return -EINVAL; + } + + return 0; +} + /** * stm32h7_spi_set_mode - configure communication mode * @spi: pointer to the spi controller data structure @@ -1267,6 +1693,36 @@ static int stm32_spi_unprepare_msg(struct spi_master *master, return 0; } +/** + * stm32f4_spi_config - Configure SPI controller as SPI master + */ +static int stm32f4_spi_config(struct stm32_spi *spi) +{ + unsigned long flags; + + spin_lock_irqsave(&spi->lock, flags); + + /* Ensure I2SMOD bit is kept cleared */ + stm32_spi_clr_bits(spi, STM32F4_SPI_I2SCFGR, + STM32F4_SPI_I2SCFGR_I2SMOD); + + /* + * - SS input value high + * - transmitter half duplex direction + * - Set the master mode (default Motorola mode) + * - Consider 1 master/n slaves configuration and + * SS input value is determined by the SSI bit + */ + stm32_spi_set_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SSI | + STM32F4_SPI_CR1_BIDIOE | + STM32F4_SPI_CR1_MSTR | + STM32F4_SPI_CR1_SSM); + + spin_unlock_irqrestore(&spi->lock, flags); + + return 0; +} + /** * stm32h7_spi_config - Configure SPI controller as SPI master */ @@ -1304,6 +1760,24 @@ static int stm32h7_spi_config(struct stm32_spi *spi) return 0; } +static const struct stm32_spi_cfg stm32f4_spi_cfg = { + .regs = &stm32f4_spi_regspec, + .get_bpw_mask = stm32f4_spi_get_bpw_mask, + .disable = stm32f4_spi_disable, + .config = stm32f4_spi_config, + .set_bpw = stm32f4_spi_set_bpw, + .set_mode = stm32f4_spi_set_mode, + .transfer_one_dma_start = stm32f4_spi_transfer_one_dma_start, + .dma_tx_cb = stm32f4_spi_dma_tx_cb, + .dma_rx_cb = stm32f4_spi_dma_rx_cb, + .transfer_one_irq = stm32f4_spi_transfer_one_irq, + .irq_handler_event = stm32f4_spi_irq_event, + .irq_handler_thread = stm32f4_spi_irq_thread, + .baud_rate_div_min = STM32F4_SPI_BR_DIV_MIN, + .baud_rate_div_max = STM32F4_SPI_BR_DIV_MAX, + .has_fifo = false, +}; + static const struct stm32_spi_cfg stm32h7_spi_cfg = { .regs = &stm32h7_spi_regspec, .get_fifo_size = stm32h7_spi_get_fifo_size, @@ -1326,6 +1800,7 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = { static const struct of_device_id stm32_spi_of_match[] = { { .compatible = "st,stm32h7-spi", .data = (void *)&stm32h7_spi_cfg }, + { .compatible = "st,stm32f4-spi", .data = (void *)&stm32f4_spi_cfg }, {}, }; MODULE_DEVICE_TABLE(of, stm32_spi_of_match); -- cgit v1.2.3 From b5c61b968def698c21e1aa8ae402cca393fe491f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 7 Jan 2019 11:26:16 -0600 Subject: IB/cm: Use struct_size() in kmalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kmalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kmalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 37980c7564c0..b9416a6fca36 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -4052,8 +4052,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, atomic_long_inc(&port->counter_group[CM_RECV]. counter[attr_id - CM_ATTR_ID_OFFSET]); - work = kmalloc(sizeof(*work) + sizeof(struct sa_path_rec) * paths, - GFP_KERNEL); + work = kmalloc(struct_size(work, path, paths), GFP_KERNEL); if (!work) { ib_free_recv_mad(mad_recv_wc); return; -- cgit v1.2.3 From 02fc1848414e116b948ebd70e865b7539e5d7b8d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 7 Jan 2019 11:39:54 -0600 Subject: IB/usnic: Use struct_size() in kmalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kmalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kmalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/usnic/usnic_uiom.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c index 49275a548751..ce01a59fccc4 100644 --- a/drivers/infiniband/hw/usnic/usnic_uiom.c +++ b/drivers/infiniband/hw/usnic/usnic_uiom.c @@ -157,9 +157,8 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, off = 0; while (ret) { - chunk = kmalloc(sizeof(*chunk) + - sizeof(struct scatterlist) * - min_t(int, ret, USNIC_UIOM_PAGE_CHUNK), + chunk = kmalloc(struct_size(chunk, page_list, + min_t(int, ret, USNIC_UIOM_PAGE_CHUNK)), GFP_KERNEL); if (!chunk) { ret = -ENOMEM; -- cgit v1.2.3 From 1b4fd9de6ec7f3722c2b3e08cc5ad171c11f93be Mon Sep 17 00:00:00 2001 From: "French, Nicholas A" Date: Sun, 9 Dec 2018 02:11:18 -0500 Subject: media: lgdt330x: fix lock status reporting A typo in code cleanup commit db9c1007bc07 ("media: lgdt330x: do some cleanups at status logic") broke the FE_HAS_LOCK reporting for 3303 chips by inadvertently modifying the register mask. The broken lock status is critial as it prevents video capture cards from reporting signal strength, scanning for channels, and capturing video. Fix regression by reverting mask change. Cc: stable@vger.kernel.org # Kernel 4.17+ Fixes: db9c1007bc07 ("media: lgdt330x: do some cleanups at status logic") Signed-off-by: Nick French Reviewed-by: Laurent Pinchart Tested-by: Adam Stylinski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt330x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index 96807e134886..8abb1a510a81 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -783,7 +783,7 @@ static int lgdt3303_read_status(struct dvb_frontend *fe, if ((buf[0] & 0x02) == 0x00) *status |= FE_HAS_SYNC; - if ((buf[0] & 0xfd) == 0x01) + if ((buf[0] & 0x01) == 0x01) *status |= FE_HAS_VITERBI | FE_HAS_LOCK; break; default: -- cgit v1.2.3 From 07758747a2d7963593421b4e782b0f20a80f58d3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Dec 2018 07:14:35 -0500 Subject: media: platform: Fix missing spin_lock_init() The driver allocates the spinlock but not initialize it. Use spin_lock_init() on it to initialize it correctly. This is detected by Coccinelle semantic patch. Fixes: d2b4387f3bdf ("media: platform: Add Aspeed Video Engine driver") Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index dfec813f50a9..692e08ef38c0 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -1661,6 +1661,7 @@ static int aspeed_video_probe(struct platform_device *pdev) video->frame_rate = 30; video->dev = &pdev->dev; + spin_lock_init(&video->lock); mutex_init(&video->video_lock); init_waitqueue_head(&video->wait); INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work); -- cgit v1.2.3 From 5aad26a7eac5a15f6a87ab83da8bebc3500c1915 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 12:15:58 -0600 Subject: IB/core: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/sa_query.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 97e6d7b69abf..7925e45ea88a 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -2342,9 +2342,7 @@ static void ib_sa_add_one(struct ib_device *device) s = rdma_start_port(device); e = rdma_end_port(device); - sa_dev = kzalloc(sizeof *sa_dev + - (e - s + 1) * sizeof (struct ib_sa_port), - GFP_KERNEL); + sa_dev = kzalloc(struct_size(sa_dev, port, e - s + 1), GFP_KERNEL); if (!sa_dev) return; -- cgit v1.2.3 From e6b7b7d8a9b999ffed814267b34443155fae1245 Mon Sep 17 00:00:00 2001 From: Potnuri Bharat Teja Date: Mon, 24 Dec 2018 20:54:51 +0530 Subject: iw_cxgb4: Check for send WR also while posting write with completion WR Inorder to optimize the NVMEoF read IOPs, iw_cxgb4 posts a FW Write with Completion WQE that combines an RDMA Write WR and the subsequent RDMA Send with Invalidate WR. This patch is an extension to it, where it posts a Write with completion for RDMA WRITE WR + RDMA SEND WR combination as well. Reviewed-by: Steve Wise Signed-off-by: Potnuri Bharat Teja Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/cxgb4/qp.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 981ff5cfb5d1..03f4c66c2659 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -632,7 +632,10 @@ static void build_rdma_write_cmpl(struct t4_sq *sq, wcwr->stag_sink = cpu_to_be32(rdma_wr(wr)->rkey); wcwr->to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr); - wcwr->stag_inv = cpu_to_be32(wr->next->ex.invalidate_rkey); + if (wr->next->opcode == IB_WR_SEND) + wcwr->stag_inv = 0; + else + wcwr->stag_inv = cpu_to_be32(wr->next->ex.invalidate_rkey); wcwr->r2 = 0; wcwr->r3 = 0; @@ -726,7 +729,10 @@ static void post_write_cmpl(struct c4iw_qp *qhp, const struct ib_send_wr *wr) /* SEND_WITH_INV swsqe */ swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx]; - swsqe->opcode = FW_RI_SEND_WITH_INV; + if (wr->next->opcode == IB_WR_SEND) + swsqe->opcode = FW_RI_SEND; + else + swsqe->opcode = FW_RI_SEND_WITH_INV; swsqe->idx = qhp->wq.sq.pidx; swsqe->complete = 0; swsqe->signaled = send_signaled; @@ -1133,9 +1139,9 @@ int c4iw_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, /* * Fastpath for NVMe-oF target WRITE + SEND_WITH_INV wr chain which is * the response for small NVMEe-oF READ requests. If the chain is - * exactly a WRITE->SEND_WITH_INV and the sgl depths and lengths - * meet the requirements of the fw_ri_write_cmpl_wr work request, - * then build and post the write_cmpl WR. If any of the tests + * exactly a WRITE->SEND_WITH_INV or a WRITE->SEND and the sgl depths + * and lengths meet the requirements of the fw_ri_write_cmpl_wr work + * request, then build and post the write_cmpl WR. If any of the tests * below are not true, then we continue on with the tradtional WRITE * and SEND WRs. */ @@ -1145,7 +1151,8 @@ int c4iw_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, wr && wr->next && !wr->next->next && wr->opcode == IB_WR_RDMA_WRITE && wr->sg_list[0].length && wr->num_sge <= T4_WRITE_CMPL_MAX_SGL && - wr->next->opcode == IB_WR_SEND_WITH_INV && + (wr->next->opcode == IB_WR_SEND || + wr->next->opcode == IB_WR_SEND_WITH_INV) && wr->next->sg_list[0].length == T4_WRITE_CMPL_MAX_CQE && wr->next->num_sge == 1 && num_wrs >= 2) { post_write_cmpl(qhp, wr); -- cgit v1.2.3 From 9c6ccc035c209dda07685e8dba829a203ba17499 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Wed, 12 Dec 2018 17:49:06 +0800 Subject: RDMA/hns: Fix the bug with updating rq head pointer when flush cqe When flush cqe with srq, the driver disable to update the rq head pointer into the hardware. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 3a669451cf86..6c36e460b00b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -3789,13 +3789,16 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, roce_set_field(qpc_mask->byte_160_sq_ci_pi, V2_QPC_BYTE_160_SQ_PRODUCER_IDX_M, V2_QPC_BYTE_160_SQ_PRODUCER_IDX_S, 0); - roce_set_field(context->byte_84_rq_ci_pi, + + if (!ibqp->srq) { + roce_set_field(context->byte_84_rq_ci_pi, V2_QPC_BYTE_84_RQ_PRODUCER_IDX_M, V2_QPC_BYTE_84_RQ_PRODUCER_IDX_S, hr_qp->rq.head); - roce_set_field(qpc_mask->byte_84_rq_ci_pi, + roce_set_field(qpc_mask->byte_84_rq_ci_pi, V2_QPC_BYTE_84_RQ_PRODUCER_IDX_M, V2_QPC_BYTE_84_RQ_PRODUCER_IDX_S, 0); + } } if (attr_mask & IB_QP_AV) { @@ -4281,7 +4284,8 @@ static void hns_roce_set_qps_to_err(struct hns_roce_dev *hr_dev, u32 qpn) if (hr_qp->ibqp.uobject) { if (hr_qp->sdb_en == 1) { hr_qp->sq.head = *(int *)(hr_qp->sdb.virt_addr); - hr_qp->rq.head = *(int *)(hr_qp->rdb.virt_addr); + if (hr_qp->rdb_en == 1) + hr_qp->rq.head = *(int *)(hr_qp->rdb.virt_addr); } else { dev_warn(hr_dev->dev, "flush cqe is unsupported in userspace!\n"); return; -- cgit v1.2.3 From 4d103905eb1e4f14cb62fcf962c9d35da7005dea Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Wed, 12 Dec 2018 17:49:07 +0800 Subject: RDMA/hns: Bugfix for the scene without receiver queue In some application scenario, the user could not have receive queue when run rdma write or read operation. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 54031c5b53fa..b9ba140b50d4 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -526,7 +526,8 @@ static int hns_roce_qp_has_sq(struct ib_qp_init_attr *attr) static int hns_roce_qp_has_rq(struct ib_qp_init_attr *attr) { if (attr->qp_type == IB_QPT_XRC_INI || - attr->qp_type == IB_QPT_XRC_TGT || attr->srq) + attr->qp_type == IB_QPT_XRC_TGT || attr->srq || + !attr->cap.max_recv_wr) return 0; return 1; -- cgit v1.2.3 From 44754b95dd35ee07c462b5425ae9c4cde8c7e7c8 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Wed, 12 Dec 2018 17:49:08 +0800 Subject: RDMA/hns: Add constraint on the setting of local ACK timeout According to IB protocol, local ACK timeout shall be a 5 bit value. Currently, hip08 could not support the possible max value 31. Fail the request in this case. Signed-off-by: Yixian Liu Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 6c36e460b00b..748dc2b44a3b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -3686,10 +3686,16 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp, V2_QPC_BYTE_212_LSN_S, 0); if (attr_mask & IB_QP_TIMEOUT) { - roce_set_field(context->byte_28_at_fl, V2_QPC_BYTE_28_AT_M, - V2_QPC_BYTE_28_AT_S, attr->timeout); - roce_set_field(qpc_mask->byte_28_at_fl, V2_QPC_BYTE_28_AT_M, - V2_QPC_BYTE_28_AT_S, 0); + if (attr->timeout < 31) { + roce_set_field(context->byte_28_at_fl, + V2_QPC_BYTE_28_AT_M, V2_QPC_BYTE_28_AT_S, + attr->timeout); + roce_set_field(qpc_mask->byte_28_at_fl, + V2_QPC_BYTE_28_AT_M, V2_QPC_BYTE_28_AT_S, + 0); + } else { + dev_warn(dev, "Local ACK timeout shall be 0 to 30.\n"); + } } roce_set_field(context->byte_172_sq_psn, V2_QPC_BYTE_172_SQ_CUR_PSN_M, -- cgit v1.2.3 From 91fb4d83b88a7b544ce564c44167aad29d4154f0 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Wed, 12 Dec 2018 17:49:09 +0800 Subject: RDMA/hns: Modify the pbl ba page size for hip08 Modify the pbl ba page size to 16K for in order to support 4G MR size. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 748dc2b44a3b..9ed7e71dc437 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -1366,7 +1366,7 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) caps->mpt_ba_pg_sz = 0; caps->mpt_buf_pg_sz = 0; caps->mpt_hop_num = HNS_ROCE_CONTEXT_HOP_NUM; - caps->pbl_ba_pg_sz = 0; + caps->pbl_ba_pg_sz = 2; caps->pbl_buf_pg_sz = 0; caps->pbl_hop_num = HNS_ROCE_PBL_HOP_NUM; caps->mtt_ba_pg_sz = 0; -- cgit v1.2.3 From 1e0d0a5fd38192f23304ea2fc2b531fea7c74247 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 7 Jan 2019 07:04:14 -0500 Subject: media: s5p-mfc: fix incorrect bus assignment in virtual child device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Virtual MFC codec's child devices must not be assigned to platform bus, because they are allocated as raw 'struct device' and don't have the corresponding 'platform' part. This fixes NULL pointer access revealed recently by commit a66d972465d1 ("devres: Align data[] to ARCH_KMALLOC_MINALIGN"). Fixes: c79667dd93b0 ("media: s5p-mfc: replace custom reserved memory handling code with generic one") Reported-by: Paweł Chmiel Signed-off-by: Marek Szyprowski Tested-by: Paweł Chmiel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 8a5ba3bec3af..0a9f59d89185 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1089,7 +1089,6 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, device_initialize(child); dev_set_name(child, "%s:%s", dev_name(dev), name); child->parent = dev; - child->bus = dev->bus; child->coherent_dma_mask = dev->coherent_dma_mask; child->dma_mask = dev->dma_mask; child->release = s5p_mfc_memdev_release; -- cgit v1.2.3 From d6f66f618569b8f6cc65435b1cab4be7f0610f32 Mon Sep 17 00:00:00 2001 From: Simon Shields Date: Mon, 7 Jan 2019 11:09:26 -0800 Subject: Input: tm2-touchkey - add support for midas touchkey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The touchkey on midas boards is almost identical. The only real difference is that it uses the same register for both keycode and base. Signed-off-by: Simon Shields Signed-off-by: Paweł Chmiel Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tm2-touchkey.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index abc266e40e17..5a1fe08bdd76 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -22,12 +22,12 @@ #include #include #include +#include #include #include #define TM2_TOUCHKEY_DEV_NAME "tm2-touchkey" -#define TM2_TOUCHKEY_KEYCODE_REG 0x03 -#define TM2_TOUCHKEY_BASE_REG 0x00 + #define TM2_TOUCHKEY_CMD_LED_ON 0x10 #define TM2_TOUCHKEY_CMD_LED_OFF 0x20 #define TM2_TOUCHKEY_BIT_PRESS_EV BIT(3) @@ -40,12 +40,28 @@ enum { TM2_TOUCHKEY_KEY_BACK, }; +struct touchkey_variant { + u8 keycode_reg; + u8 base_reg; +}; + struct tm2_touchkey_data { struct i2c_client *client; struct input_dev *input_dev; struct led_classdev led_dev; struct regulator *vdd; struct regulator_bulk_data regulators[2]; + const struct touchkey_variant *variant; +}; + +static const struct touchkey_variant tm2_touchkey_variant = { + .keycode_reg = 0x03, + .base_reg = 0x00, +}; + +static const struct touchkey_variant midas_touchkey_variant = { + .keycode_reg = 0x00, + .base_reg = 0x00, }; static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev, @@ -66,7 +82,7 @@ static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev, regulator_set_voltage(touchkey->vdd, volt, volt); i2c_smbus_write_byte_data(touchkey->client, - TM2_TOUCHKEY_BASE_REG, data); + touchkey->variant->base_reg, data); } static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey) @@ -99,7 +115,7 @@ static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid) int key; data = i2c_smbus_read_byte_data(touchkey->client, - TM2_TOUCHKEY_KEYCODE_REG); + touchkey->variant->keycode_reg); if (data < 0) { dev_err(&touchkey->client->dev, "failed to read i2c data: %d\n", data); @@ -153,6 +169,8 @@ static int tm2_touchkey_probe(struct i2c_client *client, touchkey->client = client; i2c_set_clientdata(client, touchkey); + touchkey->variant = of_device_get_match_data(&client->dev); + touchkey->regulators[0].supply = "vcc"; touchkey->regulators[1].supply = "vdd"; error = devm_regulator_bulk_get(&client->dev, @@ -262,7 +280,13 @@ static const struct i2c_device_id tm2_touchkey_id_table[] = { MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table); static const struct of_device_id tm2_touchkey_of_match[] = { - { .compatible = "cypress,tm2-touchkey", }, + { + .compatible = "cypress,tm2-touchkey", + .data = &tm2_touchkey_variant, + }, { + .compatible = "cypress,midas-touchkey", + .data = &midas_touchkey_variant, + }, { }, }; MODULE_DEVICE_TABLE(of, tm2_touchkey_of_match); -- cgit v1.2.3 From d5a158cec4f33fbab031fc97fc17bfe5371925be Mon Sep 17 00:00:00 2001 From: Jonathan Bakker Date: Mon, 7 Jan 2019 11:11:04 -0800 Subject: Input: tm2-touchkey - correct initial brightness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tm2-touchkey doesn't have brightness levels, but only on/off states, so replace LED_FULL with LED_ON. Signed-off-by: Jonathan Bakker Signed-off-by: Paweł Chmiel Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tm2-touchkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index 5a1fe08bdd76..0336789ab1bb 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -230,7 +230,7 @@ static int tm2_touchkey_probe(struct i2c_client *client, /* led device */ touchkey->led_dev.name = TM2_TOUCHKEY_DEV_NAME; - touchkey->led_dev.brightness = LED_FULL; + touchkey->led_dev.brightness = LED_ON; touchkey->led_dev.max_brightness = LED_ON; touchkey->led_dev.brightness_set = tm2_touchkey_led_brightness_set; -- cgit v1.2.3 From 07df1c55270c142b5027dd31787c42d2b01e2e92 Mon Sep 17 00:00:00 2001 From: Jonathan Bakker Date: Mon, 7 Jan 2019 11:11:55 -0800 Subject: Input: tm2-touchkey - allow specifying custom keycodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all devices use the same keycodes in the same order, so add possibility to define keycodes for buttons present on actual hardware. If keycodes property is not present, we assume that device has at least MENU and BACK keys. Signed-off-by: Jonathan Bakker Signed-off-by: Paweł Chmiel Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tm2-touchkey.c | 49 +++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index 0336789ab1bb..b55faf597d8a 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -35,11 +35,6 @@ #define TM2_TOUCHKEY_LED_VOLTAGE_MIN 2500000 #define TM2_TOUCHKEY_LED_VOLTAGE_MAX 3300000 -enum { - TM2_TOUCHKEY_KEY_MENU = 0x1, - TM2_TOUCHKEY_KEY_BACK, -}; - struct touchkey_variant { u8 keycode_reg; u8 base_reg; @@ -52,6 +47,8 @@ struct tm2_touchkey_data { struct regulator *vdd; struct regulator_bulk_data regulators[2]; const struct touchkey_variant *variant; + u32 keycodes[4]; + int num_keycodes; }; static const struct touchkey_variant tm2_touchkey_variant = { @@ -112,7 +109,8 @@ static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid) { struct tm2_touchkey_data *touchkey = devid; int data; - int key; + int index; + int i; data = i2c_smbus_read_byte_data(touchkey->client, touchkey->variant->keycode_reg); @@ -122,26 +120,20 @@ static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid) goto out; } - switch (data & TM2_TOUCHKEY_BIT_KEYCODE) { - case TM2_TOUCHKEY_KEY_MENU: - key = KEY_PHONE; - break; - - case TM2_TOUCHKEY_KEY_BACK: - key = KEY_BACK; - break; - - default: + index = (data & TM2_TOUCHKEY_BIT_KEYCODE) - 1; + if (index < 0 || index >= touchkey->num_keycodes) { dev_warn(&touchkey->client->dev, - "unhandled keycode, data %#02x\n", data); + "invalid keycode index %d\n", index); goto out; } if (data & TM2_TOUCHKEY_BIT_PRESS_EV) { - input_report_key(touchkey->input_dev, KEY_PHONE, 0); - input_report_key(touchkey->input_dev, KEY_BACK, 0); + for (i = 0; i < touchkey->num_keycodes; i++) + input_report_key(touchkey->input_dev, + touchkey->keycodes[i], 0); } else { - input_report_key(touchkey->input_dev, key, 1); + input_report_key(touchkey->input_dev, + touchkey->keycodes[index], 1); } input_sync(touchkey->input_dev); @@ -153,8 +145,10 @@ out: static int tm2_touchkey_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device_node *np = client->dev.of_node; struct tm2_touchkey_data *touchkey; int error; + int i; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -184,6 +178,16 @@ static int tm2_touchkey_probe(struct i2c_client *client, /* Save VDD for easy access */ touchkey->vdd = touchkey->regulators[1].consumer; + touchkey->num_keycodes = of_property_read_variable_u32_array(np, + "linux,keycodes", touchkey->keycodes, 0, + ARRAY_SIZE(touchkey->keycodes)); + if (touchkey->num_keycodes <= 0) { + /* default keycodes */ + touchkey->keycodes[0] = KEY_PHONE; + touchkey->keycodes[1] = KEY_BACK; + touchkey->num_keycodes = 2; + } + error = tm2_touchkey_power_enable(touchkey); if (error) { dev_err(&client->dev, "failed to power up device: %d\n", error); @@ -208,8 +212,9 @@ static int tm2_touchkey_probe(struct i2c_client *client, touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME; touchkey->input_dev->id.bustype = BUS_I2C; - input_set_capability(touchkey->input_dev, EV_KEY, KEY_PHONE); - input_set_capability(touchkey->input_dev, EV_KEY, KEY_BACK); + for (i = 0; i < touchkey->num_keycodes; i++) + input_set_capability(touchkey->input_dev, EV_KEY, + touchkey->keycodes[i]); error = input_register_device(touchkey->input_dev); if (error) { -- cgit v1.2.3 From 1cdbd3e57698fa22eddb522b2c7fa6048420da5f Mon Sep 17 00:00:00 2001 From: Jonathan Bakker Date: Mon, 7 Jan 2019 11:21:16 -0800 Subject: Input: tm2-touchkey - add support for aries touchkey variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The touchkey variant found on aries board is slighty different, it uses a fixed regulator and writes/read to the same place Signed-off-by: Jonathan Bakker Signed-off-by: Paweł Chmiel Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tm2-touchkey.c | 53 ++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index b55faf597d8a..7dbef96559d2 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -28,6 +28,8 @@ #define TM2_TOUCHKEY_DEV_NAME "tm2-touchkey" +#define ARIES_TOUCHKEY_CMD_LED_ON 0x1 +#define ARIES_TOUCHKEY_CMD_LED_OFF 0x2 #define TM2_TOUCHKEY_CMD_LED_ON 0x10 #define TM2_TOUCHKEY_CMD_LED_OFF 0x20 #define TM2_TOUCHKEY_BIT_PRESS_EV BIT(3) @@ -38,6 +40,10 @@ struct touchkey_variant { u8 keycode_reg; u8 base_reg; + u8 cmd_led_on; + u8 cmd_led_off; + bool no_reg; + bool fixed_regulator; }; struct tm2_touchkey_data { @@ -54,11 +60,22 @@ struct tm2_touchkey_data { static const struct touchkey_variant tm2_touchkey_variant = { .keycode_reg = 0x03, .base_reg = 0x00, + .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON, + .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF, }; static const struct touchkey_variant midas_touchkey_variant = { .keycode_reg = 0x00, .base_reg = 0x00, + .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON, + .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF, +}; + +static struct touchkey_variant aries_touchkey_variant = { + .no_reg = true, + .fixed_regulator = true, + .cmd_led_on = ARIES_TOUCHKEY_CMD_LED_ON, + .cmd_led_off = ARIES_TOUCHKEY_CMD_LED_OFF, }; static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev, @@ -71,15 +88,20 @@ static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev, if (brightness == LED_OFF) { volt = TM2_TOUCHKEY_LED_VOLTAGE_MIN; - data = TM2_TOUCHKEY_CMD_LED_OFF; + data = touchkey->variant->cmd_led_off; } else { volt = TM2_TOUCHKEY_LED_VOLTAGE_MAX; - data = TM2_TOUCHKEY_CMD_LED_ON; + data = touchkey->variant->cmd_led_on; } - regulator_set_voltage(touchkey->vdd, volt, volt); - i2c_smbus_write_byte_data(touchkey->client, - touchkey->variant->base_reg, data); + if (!touchkey->variant->fixed_regulator) + regulator_set_voltage(touchkey->vdd, volt, volt); + + if (touchkey->variant->no_reg) + i2c_smbus_write_byte(touchkey->client, data); + else + i2c_smbus_write_byte_data(touchkey->client, + touchkey->variant->base_reg, data); } static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey) @@ -112,8 +134,11 @@ static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid) int index; int i; - data = i2c_smbus_read_byte_data(touchkey->client, - touchkey->variant->keycode_reg); + if (touchkey->variant->no_reg) + data = i2c_smbus_read_byte(touchkey->client); + else + data = i2c_smbus_read_byte_data(touchkey->client, + touchkey->variant->keycode_reg); if (data < 0) { dev_err(&touchkey->client->dev, "failed to read i2c data: %d\n", data); @@ -139,6 +164,14 @@ static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid) input_sync(touchkey->input_dev); out: + if (touchkey->variant->fixed_regulator && + data & TM2_TOUCHKEY_BIT_PRESS_EV) { + /* touch turns backlight on, so make sure we're in sync */ + if (touchkey->led_dev.brightness == LED_OFF) + tm2_touchkey_led_brightness_set(&touchkey->led_dev, + LED_OFF); + } + return IRQ_HANDLED; } @@ -246,6 +279,9 @@ static int tm2_touchkey_probe(struct i2c_client *client, return error; } + if (touchkey->variant->fixed_regulator) + tm2_touchkey_led_brightness_set(&touchkey->led_dev, LED_ON); + return 0; } @@ -291,6 +327,9 @@ static const struct of_device_id tm2_touchkey_of_match[] = { }, { .compatible = "cypress,midas-touchkey", .data = &midas_touchkey_variant, + }, { + .compatible = "cypress,aries-touchkey", + .data = &aries_touchkey_variant, }, { }, }; -- cgit v1.2.3 From e85bb0beb6498c0dffe18a2f1f16d575bc175c32 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Mon, 7 Jan 2019 11:53:59 -0800 Subject: Input: ad7879 - add check for read errors in interrupt regmap_bulk_read() can return a non zero value on failure. The fix checks if the function call succeeded before calling mod_timer. The issue was identified by a static analysis tool. Signed-off-by: Aditya Pakki Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 6fa714c587b4..3a016f43fb85 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -246,11 +246,14 @@ static void ad7879_timer(struct timer_list *t) static irqreturn_t ad7879_irq(int irq, void *handle) { struct ad7879 *ts = handle; + int error; - regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS, - ts->conversion_data, AD7879_NR_SENSE); - - if (!ad7879_report(ts)) + error = regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS, + ts->conversion_data, AD7879_NR_SENSE); + if (error) + dev_err_ratelimited(ts->dev, "failed to read %#02x: %d\n", + AD7879_REG_XPLUS, error); + else if (!ad7879_report(ts)) mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT); return IRQ_HANDLED; -- cgit v1.2.3 From f9d27de6fafce7b50a6ca6a7696f3d62aee6808e Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 17 Dec 2018 22:50:15 +0100 Subject: mtd: mtdram: Expose module parameters Since we can set module parameters also when a driver is built in, it makes no sense to protect module parameter with #ifdef MODULE. Now the mtdram sizes can also set when the module is not a loadable module. Signed-off-by: Richard Weinberger Signed-off-by: Boris Brezillon --- drivers/mtd/devices/mtdram.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index 46238796145f..1c97fabc4bf9 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -24,14 +24,12 @@ static unsigned long writebuf_size = 64; #define MTDRAM_TOTAL_SIZE (total_size * 1024) #define MTDRAM_ERASE_SIZE (erase_size * 1024) -#ifdef MODULE module_param(total_size, ulong, 0); MODULE_PARM_DESC(total_size, "Total device size in KiB"); module_param(erase_size, ulong, 0); MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); module_param(writebuf_size, ulong, 0); MODULE_PARM_DESC(writebuf_size, "Device write buf size in Bytes (Default: 64)"); -#endif // We could store these in the mtd structure, but we only support 1 device.. static struct mtd_info *mtd_info; -- cgit v1.2.3 From 48f1b4efd67c922eff113f247533cbe175b1491e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Jan 2019 13:12:33 +0100 Subject: regulator: Fix trivial language typos Fix few trivial language typos in core and drivers. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 ++++---- drivers/regulator/core.c | 16 ++++++++-------- drivers/regulator/lp8755.c | 4 ++-- drivers/regulator/of_regulator.c | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index ee60a222f5eb..7fc1f88e27e7 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -484,7 +484,7 @@ config REGULATOR_MAX8925 tristate "Maxim MAX8925 Power Management IC" depends on MFD_MAX8925 help - Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC. + Say y here to support the voltage regulator of Maxim MAX8925 PMIC. config REGULATOR_MAX8952 tristate "Maxim MAX8952 Power Management IC" @@ -501,7 +501,7 @@ config REGULATOR_MAX8973 select REGMAP_I2C help The MAXIM MAX8973 high-efficiency. three phase, DC-DC step-down - switching regulator delievers up to 9A of output current. Each + switching regulator delivers up to 9A of output current. Each phase operates at a 2MHz fixed frequency with a 120 deg shift from the adjacent phase, allowing the use of small magnetic component. @@ -646,7 +646,7 @@ config REGULATOR_PCF50633 tristate "NXP PCF50633 regulator driver" depends on MFD_PCF50633 help - Say Y here to support the voltage regulators and convertors + Say Y here to support the voltage regulators and converters on PCF50633 config REGULATOR_PFUZE100 @@ -924,7 +924,7 @@ config REGULATOR_TPS65132 select REGMAP_I2C help This driver supports TPS65132 single inductor - dual output - power supply specifcally designed for display panels. + power supply specifically designed for display panels. config REGULATOR_TPS65217 tristate "TI TPS65217 Power regulators" diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b9d7b45c7295..3f9d81b6e763 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -326,7 +326,7 @@ err_unlock: * @rdev: regulator source * @ww_ctx: w/w mutex acquire context * - * Unlock all regulators related with rdev by coupling or suppling. + * Unlock all regulators related with rdev by coupling or supplying. */ static void regulator_unlock_dependent(struct regulator_dev *rdev, struct ww_acquire_ctx *ww_ctx) @@ -341,7 +341,7 @@ static void regulator_unlock_dependent(struct regulator_dev *rdev, * @ww_ctx: w/w mutex acquire context * * This function as a wrapper on regulator_lock_recursive(), which locks - * all regulators related with rdev by coupling or suppling. + * all regulators related with rdev by coupling or supplying. */ static void regulator_lock_dependent(struct regulator_dev *rdev, struct ww_acquire_ctx *ww_ctx) @@ -1003,7 +1003,7 @@ static int suspend_set_state(struct regulator_dev *rdev, if (rstate == NULL) return 0; - /* If we have no suspend mode configration don't set anything; + /* If we have no suspend mode configuration don't set anything; * only warn if the driver implements set_suspend_voltage or * set_suspend_mode callback. */ @@ -1131,7 +1131,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, int current_uV = _regulator_get_voltage(rdev); if (current_uV == -ENOTRECOVERABLE) { - /* This regulator can't be read and must be initted */ + /* This regulator can't be read and must be initialized */ rdev_info(rdev, "Setting %d-%duV\n", rdev->constraints->min_uV, rdev->constraints->max_uV); @@ -1780,7 +1780,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) struct device *dev = rdev->dev.parent; int ret; - /* No supply to resovle? */ + /* No supply to resolve? */ if (!rdev->supply_name) return 0; @@ -2409,7 +2409,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) * timer wrapping. * in case of multiple timer wrapping, either it can be * detected by out-of-range remaining, or it cannot be - * detected and we gets a panelty of + * detected and we get a penalty of * _regulator_enable_delay(). */ remaining = intended - start_jiffy; @@ -2809,7 +2809,7 @@ static void regulator_disable_work(struct work_struct *work) /** * regulator_disable_deferred - disable regulator output with delay * @regulator: regulator source - * @ms: miliseconds until the regulator is disabled + * @ms: milliseconds until the regulator is disabled * * Execute regulator_disable() on the regulator after a delay. This * is intended for use with devices that require some time to quiesce. @@ -4943,7 +4943,7 @@ regulator_register(const struct regulator_desc *regulator_desc, * device tree until we have handled it over to the core. If the * config that was passed in to this function DOES NOT contain * a descriptor, and the config after this call DOES contain - * a descriptor, we definately got one from parsing the device + * a descriptor, we definitely got one from parsing the device * tree. */ if (!cfg->ena_gpiod && config->ena_gpiod) diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index 244822bb63cd..6d229ad4ef3e 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -386,7 +386,7 @@ static irqreturn_t lp8755_irq_handler(int irq, void *data) if (ret < 0) goto err_i2c; - /* send OCP event to all regualtor devices */ + /* send OCP event to all regulator devices */ if ((flag1 & 0x01) && (pchip->irqmask & 0x01)) for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) if (pchip->rdev[icnt] != NULL) @@ -394,7 +394,7 @@ static irqreturn_t lp8755_irq_handler(int irq, void *data) LP8755_EVENT_OCP, NULL); - /* send OVP event to all regualtor devices */ + /* send OVP event to all regulator devices */ if ((flag1 & 0x02) && (pchip->irqmask & 0x02)) for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) if (pchip->rdev[icnt] != NULL) diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index ffa5fc3724e4..7b6bf3536271 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -255,7 +255,7 @@ static void of_get_regulation_constraints(struct device_node *np, * @desc: regulator description * * Populates regulator_init_data structure by extracting data from device - * tree node, returns a pointer to the populated struture or NULL if memory + * tree node, returns a pointer to the populated structure or NULL if memory * alloc fails. */ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, @@ -547,7 +547,7 @@ bool of_check_coupling_data(struct regulator_dev *rdev) NULL); if (c_n_phandles != n_phandles) { - dev_err(&rdev->dev, "number of couped reg phandles mismatch\n"); + dev_err(&rdev->dev, "number of coupled reg phandles mismatch\n"); ret = false; goto clean; } -- cgit v1.2.3 From 2e7189b6c774adc6b848808286b14d0825dc9d1a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 Jul 2018 09:33:17 +0200 Subject: driver core: bus: convert to use BUS_ATTR_WO and RW We are trying to get rid of BUS_ATTR() and the usage of that in bus.c can be trivially converted to use BUS_ATTR_WO and RW, so use those macros instead. Cc: "Rafael J. Wysocki" Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index e06a57936cc9..a56e865cdbfa 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -236,12 +236,12 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, } static DRIVER_ATTR_IGNORE_LOCKDEP(bind, S_IWUSR, NULL, bind_store); -static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf) +static ssize_t drivers_autoprobe_show(struct bus_type *bus, char *buf) { return sprintf(buf, "%d\n", bus->p->drivers_autoprobe); } -static ssize_t store_drivers_autoprobe(struct bus_type *bus, +static ssize_t drivers_autoprobe_store(struct bus_type *bus, const char *buf, size_t count) { if (buf[0] == '0') @@ -251,7 +251,7 @@ static ssize_t store_drivers_autoprobe(struct bus_type *bus, return count; } -static ssize_t store_drivers_probe(struct bus_type *bus, +static ssize_t drivers_probe_store(struct bus_type *bus, const char *buf, size_t count) { struct device *dev; @@ -586,9 +586,8 @@ static void remove_bind_files(struct device_driver *drv) driver_remove_file(drv, &driver_attr_unbind); } -static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); -static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, - show_drivers_autoprobe, store_drivers_autoprobe); +static BUS_ATTR_WO(drivers_probe); +static BUS_ATTR_RW(drivers_autoprobe); static int add_probe_files(struct bus_type *bus) { -- cgit v1.2.3 From a4723041857eaa35f189d237da769c4c63235544 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 29 Oct 2018 16:31:26 +0100 Subject: driver core: drop use of BUS_ATTR() We are trying to get rid of BUS_ATTR() so drop the last user of it from the tree. We had to "open code" it in order to prevent a function name conflict due to the use of DEVICE_ATTR_WO() earlier in the file :( Cc: "Rafael J. Wysocki" Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index a56e865cdbfa..3ab45843da39 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -837,7 +837,14 @@ static ssize_t bus_uevent_store(struct bus_type *bus, rc = kobject_synth_uevent(&bus->p->subsys.kobj, buf, count); return rc ? rc : count; } -static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); +/* + * "open code" the old BUS_ATTR() macro here. We want to use BUS_ATTR_WO() + * here, but can not use it as earlier in the file we have + * DEVICE_ATTR_WO(uevent), which would cause a clash with the with the store + * function name. + */ +static struct bus_attribute bus_attr_uevent = __ATTR(uevent, S_IWUSR, NULL, + bus_uevent_store); /** * bus_register - register a driver-core subsystem -- cgit v1.2.3 From 6756f4c375db11af7039985636bddde676615a94 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 09:22:25 -0600 Subject: USB: core: urb: Use struct_size() in kmalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kmalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kmalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/urb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index f51750bcd152..0eab79f82ce4 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -70,9 +70,8 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { struct urb *urb; - urb = kmalloc(sizeof(struct urb) + - iso_packets * sizeof(struct usb_iso_packet_descriptor), - mem_flags); + urb = kmalloc(struct_size(urb, iso_frame_desc, iso_packets), + mem_flags); if (!urb) return NULL; usb_init_urb(urb); -- cgit v1.2.3 From db4a6cbf699a4b11e358621cb22d452c986842ee Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 21 Dec 2018 14:10:23 +0300 Subject: serial: clps711x: Remove board support Since board support for the CLPS711X platform was removed (commit 4a56f46a7dc6 ("ARM: clps711x: Remove boards support")), remove the board support from the driver. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/clps711x.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 98f193a83392..061590795680 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -442,14 +442,10 @@ static struct console clps711x_console = { static int uart_clps711x_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int ret, index = np ? of_alias_get_id(np, "serial") : pdev->id; struct clps711x_port *s; struct resource *res; struct clk *uart_clk; - int irq; - - if (index < 0 || index >= UART_CLPS711X_NR) - return -EINVAL; + int irq, ret; s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); if (!s) @@ -473,20 +469,11 @@ static int uart_clps711x_probe(struct platform_device *pdev) if (s->rx_irq < 0) return s->rx_irq; - if (!np) { - char syscon_name[9]; - - sprintf(syscon_name, "syscon.%i", index + 1); - s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name); - if (IS_ERR(s->syscon)) - return PTR_ERR(s->syscon); - } else { - s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(s->syscon)) - return PTR_ERR(s->syscon); - } + s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(s->syscon)) + return PTR_ERR(s->syscon); - s->port.line = index; + s->port.line = of_alias_get_id(np, "serial"); s->port.dev = &pdev->dev; s->port.iotype = UPIO_MEM32; s->port.mapbase = res->start; -- cgit v1.2.3 From 51f689cc11333944c7a457f25ec75fcb41e99410 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Tue, 25 Dec 2018 19:26:19 -0600 Subject: serial: max310x: pass return value of spi_register_driver spi_register_driver() may fail, so let's pass its return value upstream. Signed-off-by: Kangjie Lu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 4f479841769a..eb040d8292a8 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1467,10 +1467,10 @@ static int __init max310x_uart_init(void) return ret; #ifdef CONFIG_SPI_MASTER - spi_register_driver(&max310x_spi_driver); + ret = spi_register_driver(&max310x_spi_driver); #endif - return 0; + return ret; } module_init(max310x_uart_init); -- cgit v1.2.3 From 84f1c5c0174ace114af318c8de35c3eeb0d04495 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 11:48:19 -0600 Subject: sc16is7xx: Use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 268098681856..635178cf3eed 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1187,9 +1187,7 @@ static int sc16is7xx_probe(struct device *dev, return PTR_ERR(regmap); /* Alloc port structure */ - s = devm_kzalloc(dev, sizeof(*s) + - sizeof(struct sc16is7xx_one) * devtype->nr_uart, - GFP_KERNEL); + s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL); if (!s) { dev_err(dev, "Error allocating port structure\n"); return -ENOMEM; -- cgit v1.2.3 From 833954a4e34ed090a8e2f3b3a8d4624002f29d30 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 15:39:13 -0600 Subject: serial: max310x: Use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index eb040d8292a8..0a04c053654f 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1197,8 +1197,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, return PTR_ERR(regmap); /* Alloc port structure */ - s = devm_kzalloc(dev, sizeof(*s) + - sizeof(struct max310x_one) * devtype->nr, GFP_KERNEL); + s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); if (!s) { dev_err(dev, "Error allocating port structure\n"); return -ENOMEM; -- cgit v1.2.3 From 11b3770d54b28dcd905155a6d4aa551187ff00eb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 7 Jan 2019 17:23:17 +0100 Subject: serial: sh-sci: Extract sci_dma_rx_chan_invalidate() The cookies and channel pointer for the DMA receive channel are invalidated in two places, and one more is planned. Extract this functionality in a common helper. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 8df0fd824520..4c75468680cb 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1243,12 +1243,22 @@ static int sci_dma_rx_find_active(struct sci_port *s) return -1; } +static void sci_dma_rx_chan_invalidate(struct sci_port *s) +{ + unsigned int i; + + s->chan_rx = NULL; + for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++) + s->cookie_rx[i] = -EINVAL; + s->active_rx = 0; +} + static void sci_rx_dma_release(struct sci_port *s) { struct dma_chan *chan = s->chan_rx_saved; - s->chan_rx_saved = s->chan_rx = NULL; - s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + s->chan_rx_saved = NULL; + sci_dma_rx_chan_invalidate(s); dmaengine_terminate_sync(chan); dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], sg_dma_address(&s->sg_rx[0])); @@ -1367,10 +1377,7 @@ fail: spin_lock_irqsave(&port->lock, flags); if (i) dmaengine_terminate_async(chan); - for (i = 0; i < 2; i++) - s->cookie_rx[i] = -EINVAL; - s->active_rx = 0; - s->chan_rx = NULL; + sci_dma_rx_chan_invalidate(s); sci_start_rx(port); if (!port_lock_held) spin_unlock_irqrestore(&port->lock, flags); -- cgit v1.2.3 From 38766e4b612ba10844afadf2fce12f8f90465c64 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 7 Jan 2019 17:23:18 +0100 Subject: serial: sh-sci: Extract sci_dma_rx_reenable_irq() Extract the functionality to direct new serial port interrupts back to the CPU into its own helper, to prepare for using it from a second callsite. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 4c75468680cb..4d814c30c418 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1274,6 +1274,20 @@ static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec) hrtimer_start(hrt, t, HRTIMER_MODE_REL); } +static void sci_dma_rx_reenable_irq(struct sci_port *s) +{ + struct uart_port *port = &s->port; + u16 scr; + + /* Direct new serial port interrupts back to CPU */ + scr = serial_port_in(port, SCSCR); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + scr &= ~SCSCR_RDRQE; + enable_irq(s->irqs[SCIx_RXI_IRQ]); + } + serial_port_out(port, SCSCR, scr | SCSCR_RIE); +} + static void sci_dma_rx_complete(void *arg) { struct sci_port *s = arg; @@ -1453,7 +1467,6 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) unsigned long flags; unsigned int read; int active, count; - u16 scr; dev_dbg(port->dev, "DMA Rx timed out\n"); @@ -1503,13 +1516,7 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) sci_submit_rx(s, true); - /* Direct new serial port interrupts back to CPU */ - scr = serial_port_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~SCSCR_RDRQE; - enable_irq(s->irqs[SCIx_RXI_IRQ]); - } - serial_port_out(port, SCSCR, scr | SCSCR_RIE); + sci_dma_rx_reenable_irq(s); spin_unlock_irqrestore(&port->lock, flags); -- cgit v1.2.3 From 26f073993665683f1debf4d66d8bc274ac6df771 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 7 Jan 2019 17:23:19 +0100 Subject: serial: sh-sci: Fix fallback to PIO in sci_dma_rx_complete() When submitting a DMA request fails in sci_dma_rx_complete(), the driver tries to fall back to PIO, but that does not work: no more data will be received, or the kernel will even crash. Fix this similar as in (but not identical to) sci_submit_rx(): - On SCIF, PIO cannot take over if any DMA transactions are pending, hence they must be terminated first. - All active cookies must be invalidated, else rx_timer_fn() may trigger a NULL pointer dereference. - Restarting the port is not needed, as it is already running, but serial port interrupts must be directed back from the DMA engine to the CPU. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 4d814c30c418..891833315698 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1337,8 +1337,9 @@ fail: dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); /* Switch to PIO */ spin_lock_irqsave(&port->lock, flags); - s->chan_rx = NULL; - sci_start_rx(port); + dmaengine_terminate_async(chan); + sci_dma_rx_chan_invalidate(s); + sci_dma_rx_reenable_irq(s); spin_unlock_irqrestore(&port->lock, flags); } -- cgit v1.2.3 From 8fcf7a6569790fb5be4e5fa7d1a9f10734c6e8d8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 7 Jan 2019 17:23:20 +0100 Subject: serial: sh-sci: Make RX/TX DMA function names consistent Most RX/TX-specific DMA functions are prefixed with "sci_dma_[rt]x_". Rename the exceptions to increase consistency. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 891833315698..cb3d5d37674f 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1253,7 +1253,7 @@ static void sci_dma_rx_chan_invalidate(struct sci_port *s) s->active_rx = 0; } -static void sci_rx_dma_release(struct sci_port *s) +static void sci_dma_rx_release(struct sci_port *s) { struct dma_chan *chan = s->chan_rx_saved; @@ -1343,7 +1343,7 @@ fail: spin_unlock_irqrestore(&port->lock, flags); } -static void sci_tx_dma_release(struct sci_port *s) +static void sci_dma_tx_release(struct sci_port *s) { struct dma_chan *chan = s->chan_tx_saved; @@ -1356,7 +1356,7 @@ static void sci_tx_dma_release(struct sci_port *s) dma_release_channel(chan); } -static int sci_submit_rx(struct sci_port *s, bool port_lock_held) +static int sci_dma_rx_submit(struct sci_port *s, bool port_lock_held) { struct dma_chan *chan = s->chan_rx; struct uart_port *port = &s->port; @@ -1399,7 +1399,7 @@ fail: return -EAGAIN; } -static void work_fn_tx(struct work_struct *work) +static void sci_dma_tx_work_fn(struct work_struct *work) { struct sci_port *s = container_of(work, struct sci_port, work_tx); struct dma_async_tx_descriptor *desc; @@ -1458,7 +1458,7 @@ switch_to_pio: return; } -static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) +static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) { struct sci_port *s = container_of(t, struct sci_port, rx_timer); struct dma_chan *chan = s->chan_rx; @@ -1515,7 +1515,7 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) } if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - sci_submit_rx(s, true); + sci_dma_rx_submit(s, true); sci_dma_rx_reenable_irq(s); @@ -1595,7 +1595,7 @@ static void sci_request_dma(struct uart_port *port) __func__, UART_XMIT_SIZE, port->state->xmit.buf, &s->tx_dma_addr); - INIT_WORK(&s->work_tx, work_fn_tx); + INIT_WORK(&s->work_tx, sci_dma_tx_work_fn); s->chan_tx_saved = s->chan_tx = chan; } } @@ -1630,12 +1630,12 @@ static void sci_request_dma(struct uart_port *port) } hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - s->rx_timer.function = rx_timer_fn; + s->rx_timer.function = sci_dma_rx_timer_fn; s->chan_rx_saved = s->chan_rx = chan; if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - sci_submit_rx(s, false); + sci_dma_rx_submit(s, false); } } @@ -1644,9 +1644,9 @@ static void sci_free_dma(struct uart_port *port) struct sci_port *s = to_sci_port(port); if (s->chan_tx_saved) - sci_tx_dma_release(s); + sci_dma_tx_release(s); if (s->chan_rx_saved) - sci_rx_dma_release(s); + sci_dma_rx_release(s); } static void sci_flush_buffer(struct uart_port *port) @@ -1684,7 +1684,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) disable_irq_nosync(irq); scr |= SCSCR_RDRQE; } else { - if (sci_submit_rx(s, false) < 0) + if (sci_dma_rx_submit(s, false) < 0) goto handle_pio; scr &= ~SCSCR_RIE; -- cgit v1.2.3 From 9e06d55f7b856bfaf82036b50072600b21e52d20 Mon Sep 17 00:00:00 2001 From: Ryan Case Date: Mon, 7 Jan 2019 17:58:35 -0800 Subject: tty: serial: qcom_geni_serial: Remove use of *_relaxed() and mb() A frequent side comment has been to remove the use of writel_relaxed, readl_relaxed, and mb. This reduces driver complexity and the _relaxed variants were not known to provide any noticeable performance benefit. Signed-off-by: Ryan Case Reviewed-by: Evan Green Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 191 ++++++++++++++-------------------- 1 file changed, 80 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index a72d6d9fb983..15c409d226c1 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -228,7 +228,7 @@ static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport) if (uart_console(uport) || !uart_cts_enabled(uport)) { mctrl |= TIOCM_CTS; } else { - geni_ios = readl_relaxed(uport->membase + SE_GENI_IOS); + geni_ios = readl(uport->membase + SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) mctrl |= TIOCM_CTS; } @@ -246,7 +246,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, if (!(mctrl & TIOCM_RTS)) uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; - writel_relaxed(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); } static const char *qcom_geni_serial_get_type(struct uart_port *uport) @@ -275,9 +275,6 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, unsigned int fifo_bits; unsigned long timeout_us = 20000; - /* Ensure polling is not re-ordered before the prior writes/reads */ - mb(); - if (uport->private_data) { port = to_dev_port(uport, uport); baud = port->baud; @@ -297,7 +294,7 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, */ timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10; while (timeout_us) { - reg = readl_relaxed(uport->membase + offset); + reg = readl(uport->membase + offset); if ((bool)(reg & field) == set) return true; udelay(10); @@ -310,7 +307,7 @@ static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size) { u32 m_cmd; - writel_relaxed(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN); + writel(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN); m_cmd = UART_START_TX << M_OPCODE_SHFT; writel(m_cmd, uport->membase + SE_GENI_M_CMD0); } @@ -323,13 +320,13 @@ static void qcom_geni_serial_poll_tx_done(struct uart_port *uport) done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_DONE_EN, true); if (!done) { - writel_relaxed(M_GENI_CMD_ABORT, uport->membase + + writel(M_GENI_CMD_ABORT, uport->membase + SE_GENI_M_CMD_CTRL_REG); irq_clear |= M_CMD_ABORT_EN; qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); } - writel_relaxed(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR); } static void qcom_geni_serial_abort_rx(struct uart_port *uport) @@ -339,8 +336,8 @@ static void qcom_geni_serial_abort_rx(struct uart_port *uport) writel(S_GENI_CMD_ABORT, uport->membase + SE_GENI_S_CMD_CTRL_REG); qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, S_GENI_CMD_ABORT, false); - writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG); + writel(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); + writel(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG); } #ifdef CONFIG_CONSOLE_POLL @@ -349,19 +346,13 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) u32 rx_fifo; u32 status; - status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); - writel_relaxed(status, uport->membase + SE_GENI_M_IRQ_CLEAR); - - status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); - writel_relaxed(status, uport->membase + SE_GENI_S_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); + writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR); - /* - * Ensure the writes to clear interrupts is not re-ordered after - * reading the data. - */ - mb(); + status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); + writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR); - status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS); + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); if (!(status & RX_FIFO_WC_MSK)) return NO_POLL_CHAR; @@ -374,13 +365,12 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport, { struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - writel_relaxed(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG); qcom_geni_serial_setup_tx(uport, 1); WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_TX_FIFO_WATERMARK_EN, true)); - writel_relaxed(c, uport->membase + SE_GENI_TX_FIFOn); - writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(c, uport->membase + SE_GENI_TX_FIFOn); + writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_poll_tx_done(uport); } #endif @@ -388,7 +378,7 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport, #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch) { - writel_relaxed(ch, uport->membase + SE_GENI_TX_FIFOn); + writel(ch, uport->membase + SE_GENI_TX_FIFOn); } static void @@ -407,7 +397,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, bytes_to_send++; } - writel_relaxed(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); qcom_geni_serial_setup_tx(uport, bytes_to_send); for (i = 0; i < count; ) { size_t chars_to_write = 0; @@ -425,7 +415,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, chars_to_write = min_t(size_t, count - i, avail / 2); uart_console_write(uport, s + i, chars_to_write, qcom_geni_serial_wr_char); - writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + + writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); i += chars_to_write; } @@ -454,7 +444,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, else spin_lock_irqsave(&uport->lock, flags); - geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); + geni_status = readl(uport->membase + SE_GENI_STATUS); /* Cancel the current write to log the fault */ if (!locked) { @@ -464,11 +454,10 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, geni_se_abort_m_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); - writel_relaxed(M_CMD_ABORT_EN, uport->membase + + writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } - writel_relaxed(M_CMD_CANCEL_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) { /* * It seems we can't interrupt existing transfers if all data @@ -477,9 +466,8 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, qcom_geni_serial_poll_tx_done(uport); if (uart_circ_chars_pending(&uport->state->xmit)) { - irq_en = readl_relaxed(uport->membase + - SE_GENI_M_IRQ_EN); - writel_relaxed(irq_en | M_TX_FIFO_WATERMARK_EN, + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + writel(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_EN); } } @@ -583,12 +571,12 @@ static void qcom_geni_serial_start_tx(struct uart_port *uport) if (!qcom_geni_serial_tx_empty(uport)) return; - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; - writel_relaxed(port->tx_wm, uport->membase + + writel(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG); - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } } @@ -598,35 +586,28 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport) u32 status; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); irq_en &= ~M_CMD_DONE_EN; if (port->xfer_mode == GENI_SE_FIFO) { irq_en &= ~M_TX_FIFO_WATERMARK_EN; - writel_relaxed(0, uport->membase + + writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG); } - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); + status = readl(uport->membase + SE_GENI_STATUS); /* Possible stop tx is called multiple times. */ if (!(status & M_GENI_CMD_ACTIVE)) return; - /* - * Ensure cancel command write is not re-ordered before checking - * the status of the Primary Sequencer. - */ - mb(); - geni_se_cancel_m_cmd(&port->se); if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_CANCEL_EN, true)) { geni_se_abort_m_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); - writel_relaxed(M_CMD_ABORT_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } - writel_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } static void qcom_geni_serial_start_rx(struct uart_port *uport) @@ -635,26 +616,20 @@ static void qcom_geni_serial_start_rx(struct uart_port *uport) u32 status; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + status = readl(uport->membase + SE_GENI_STATUS); if (status & S_GENI_CMD_ACTIVE) qcom_geni_serial_stop_rx(uport); - /* - * Ensure setup command write is not re-ordered before checking - * the status of the Secondary Sequencer. - */ - mb(); - geni_se_setup_s_cmd(&port->se, UART_START_READ, 0); if (port->xfer_mode == GENI_SE_FIFO) { - irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; - writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } } @@ -666,31 +641,25 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport) u32 irq_clear = S_CMD_DONE_EN; if (port->xfer_mode == GENI_SE_FIFO) { - irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); - writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + status = readl(uport->membase + SE_GENI_STATUS); /* Possible stop rx is called multiple times. */ if (!(status & S_GENI_CMD_ACTIVE)) return; - /* - * Ensure cancel command write is not re-ordered before checking - * the status of the Secondary Sequencer. - */ - mb(); - geni_se_cancel_s_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, S_GENI_CMD_CANCEL, false); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); - writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_STATUS); + writel(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); if (status & S_GENI_CMD_ACTIVE) qcom_geni_serial_abort_rx(uport); } @@ -704,7 +673,7 @@ static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop) u32 total_bytes; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS); + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); word_cnt = status & RX_FIFO_WC_MSK; last_word_partial = status & RX_LAST; last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >> @@ -734,7 +703,7 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, unsigned int chunk; int tail; - status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS); + status = readl(uport->membase + SE_GENI_TX_FIFO_STATUS); /* Complete the current tx command before taking newly added data */ if (active) @@ -760,9 +729,9 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, qcom_geni_serial_setup_tx(uport, pending); port->tx_remaining = pending; - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); if (!(irq_en & M_TX_FIFO_WATERMARK_EN)) - writel_relaxed(irq_en | M_TX_FIFO_WATERMARK_EN, + writel(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_EN); } @@ -795,14 +764,14 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, * cleared it in qcom_geni_serial_isr it will have already reasserted * so we must clear it again here after our writes. */ - writel_relaxed(M_TX_FIFO_WATERMARK_EN, + writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); out_write_wakeup: if (!port->tx_remaining) { - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); if (irq_en & M_TX_FIFO_WATERMARK_EN) - writel_relaxed(irq_en & ~M_TX_FIFO_WATERMARK_EN, + writel(irq_en & ~M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_EN); } @@ -826,12 +795,12 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) return IRQ_NONE; spin_lock_irqsave(&uport->lock, flags); - m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); - s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); - geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); - m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); + m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); + s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); + geni_status = readl(uport->membase + SE_GENI_STATUS); + m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + writel(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN)) goto out_unlock; @@ -929,7 +898,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) get_tx_fifo_size(port); set_rfr_wm(port); - writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT); + writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT); /* * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. @@ -1033,10 +1002,10 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, ser_clk_cfg |= clk_div << CLK_DIV_SHFT; /* parity */ - tx_trans_cfg = readl_relaxed(uport->membase + SE_UART_TX_TRANS_CFG); - tx_parity_cfg = readl_relaxed(uport->membase + SE_UART_TX_PARITY_CFG); - rx_trans_cfg = readl_relaxed(uport->membase + SE_UART_RX_TRANS_CFG); - rx_parity_cfg = readl_relaxed(uport->membase + SE_UART_RX_PARITY_CFG); + tx_trans_cfg = readl(uport->membase + SE_UART_TX_TRANS_CFG); + tx_parity_cfg = readl(uport->membase + SE_UART_TX_PARITY_CFG); + rx_trans_cfg = readl(uport->membase + SE_UART_RX_TRANS_CFG); + rx_parity_cfg = readl(uport->membase + SE_UART_RX_PARITY_CFG); if (termios->c_cflag & PARENB) { tx_trans_cfg |= UART_TX_PAR_EN; rx_trans_cfg |= UART_RX_PAR_EN; @@ -1092,17 +1061,17 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, uart_update_timeout(uport, termios->c_cflag, baud); if (!uart_console(uport)) - writel_relaxed(port->loopback, + writel(port->loopback, uport->membase + SE_UART_LOOPBACK_CFG); - writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); - writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); - writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); - writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); - writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); - writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); - writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); - writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); - writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); + writel(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); + writel(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); + writel(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); + writel(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); + writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); + writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); + writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); + writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); + writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); out_restart_rx: qcom_geni_serial_start_rx(uport); } @@ -1193,13 +1162,13 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev, geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2); geni_se_select_mode(&se, GENI_SE_FIFO); - writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); - writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); - writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); - writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); - writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); - writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); - writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); + writel(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); + writel(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); + writel(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); + writel(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); + writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); + writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); + writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); dev->con->write = qcom_geni_serial_earlycon_write; dev->con->setup = NULL; -- cgit v1.2.3 From a85fb9ce1fab34a3216fd4d769fede643dbc68d4 Mon Sep 17 00:00:00 2001 From: Ryan Case Date: Mon, 7 Jan 2019 17:58:36 -0800 Subject: tty: serial: qcom_geni_serial: Remove set_rfr_wm() and related variables The variables of tx_wm and rx_wm were set to the same define value in all cases, never updated, and the define was sometimes used interchangably. Remove the variables/function and use the fixed value. Signed-off-by: Ryan Case Reviewed-by: Evan Green Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 15c409d226c1..b8416980cb02 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -89,7 +89,7 @@ #define DEF_FIFO_DEPTH_WORDS 16 #define DEF_TX_WM 2 #define DEF_FIFO_WIDTH_BITS 32 -#define UART_CONSOLE_RX_WM 2 +#define UART_RX_WM 2 #define MAX_LOOPBACK_CFG 3 #ifdef CONFIG_CONSOLE_POLL @@ -105,9 +105,6 @@ struct qcom_geni_serial_port { u32 tx_fifo_depth; u32 tx_fifo_width; u32 rx_fifo_depth; - u32 tx_wm; - u32 rx_wm; - u32 rx_rfr; enum geni_se_xfer_mode xfer_mode; bool setup; int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop); @@ -363,9 +360,7 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) static void qcom_geni_serial_poll_put_char(struct uart_port *uport, unsigned char c) { - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - - writel(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); qcom_geni_serial_setup_tx(uport, 1); WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_TX_FIFO_WATERMARK_EN, true)); @@ -574,7 +569,7 @@ static void qcom_geni_serial_start_tx(struct uart_port *uport) irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; - writel(port->tx_wm, uport->membase + + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } @@ -846,17 +841,6 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port) (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE; } -static void set_rfr_wm(struct qcom_geni_serial_port *port) -{ - /* - * Set RFR (Flow off) to FIFO_DEPTH - 2. - * RX WM level at 10% RX_FIFO_DEPTH. - * TX WM level at 10% TX_FIFO_DEPTH. - */ - port->rx_rfr = port->rx_fifo_depth - 2; - port->rx_wm = UART_CONSOLE_RX_WM; - port->tx_wm = DEF_TX_WM; -} static void qcom_geni_serial_shutdown(struct uart_port *uport) { @@ -897,7 +881,6 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) get_tx_fifo_size(port); - set_rfr_wm(port); writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT); /* * Make an unconditional cancel on the main sequencer to reset @@ -910,7 +893,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) false, true, false); geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw, false, false, true); - geni_se_init(&port->se, port->rx_wm, port->rx_rfr); + geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2); geni_se_select_mode(&port->se, port->xfer_mode); if (!uart_console(uport)) { port->rx_fifo = devm_kcalloc(uport->dev, -- cgit v1.2.3 From bdc05a8a3f822ca0662464055f902faf760da6be Mon Sep 17 00:00:00 2001 From: Ryan Case Date: Mon, 7 Jan 2019 17:58:37 -0800 Subject: tty: serial: qcom_geni_serial: Remove xfer_mode variable The driver only supports FIFO mode so setting and checking this variable is unnecessary. If DMA support is ever added then such checks can be introduced. Signed-off-by: Ryan Case Reviewed-by: Evan Green Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 67 +++++++++++++---------------------- 1 file changed, 24 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index b8416980cb02..6774da6435fa 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -105,7 +105,6 @@ struct qcom_geni_serial_port { u32 tx_fifo_depth; u32 tx_fifo_width; u32 rx_fifo_depth; - enum geni_se_xfer_mode xfer_mode; bool setup; int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop); unsigned int baud; @@ -550,29 +549,20 @@ static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop) static void qcom_geni_serial_start_tx(struct uart_port *uport) { u32 irq_en; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); u32 status; - if (port->xfer_mode == GENI_SE_FIFO) { - /* - * readl ensures reading & writing of IRQ_EN register - * is not re-ordered before checking the status of the - * Serial Engine. - */ - status = readl(uport->membase + SE_GENI_STATUS); - if (status & M_GENI_CMD_ACTIVE) - return; + status = readl(uport->membase + SE_GENI_STATUS); + if (status & M_GENI_CMD_ACTIVE) + return; - if (!qcom_geni_serial_tx_empty(uport)) - return; + if (!qcom_geni_serial_tx_empty(uport)) + return; - irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); - irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; - writel(DEF_TX_WM, uport->membase + - SE_GENI_TX_WATERMARK_REG); - writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } static void qcom_geni_serial_stop_tx(struct uart_port *uport) @@ -582,12 +572,8 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport) struct qcom_geni_serial_port *port = to_dev_port(uport, uport); irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); - irq_en &= ~M_CMD_DONE_EN; - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en &= ~M_TX_FIFO_WATERMARK_EN; - writel(0, uport->membase + - SE_GENI_TX_WATERMARK_REG); - } + irq_en &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN); + writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG); writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); status = readl(uport->membase + SE_GENI_STATUS); /* Possible stop tx is called multiple times. */ @@ -617,15 +603,13 @@ static void qcom_geni_serial_start_rx(struct uart_port *uport) geni_se_setup_s_cmd(&port->se, UART_START_READ, 0); - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); - irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; - writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); + irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); - irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); - irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; - writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } static void qcom_geni_serial_stop_rx(struct uart_port *uport) @@ -635,15 +619,13 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport) struct qcom_geni_serial_port *port = to_dev_port(uport, uport); u32 irq_clear = S_CMD_DONE_EN; - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); - irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); - writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); + irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); - irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); - irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); - writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); status = readl(uport->membase + SE_GENI_STATUS); /* Possible stop rx is called multiple times. */ @@ -886,7 +868,6 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. */ - port->xfer_mode = GENI_SE_FIFO; if (uart_console(uport)) qcom_geni_serial_poll_tx_done(uport); geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw, @@ -894,7 +875,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw, false, false, true); geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2); - geni_se_select_mode(&port->se, port->xfer_mode); + geni_se_select_mode(&port->se, GENI_SE_FIFO); if (!uart_console(uport)) { port->rx_fifo = devm_kcalloc(uport->dev, port->rx_fifo_depth, sizeof(u32), GFP_KERNEL); -- cgit v1.2.3 From 385298abbe968e9eb30b8f84e22e5165ebe2dd9f Mon Sep 17 00:00:00 2001 From: Ryan Case Date: Mon, 7 Jan 2019 17:58:38 -0800 Subject: tty: serial: qcom_geni_serial: Use u32 for register variables Use u32 rather than unsigned long for register variables for clarity and consistency. Signed-off-by: Ryan Case Reviewed-by: Stephen Boyd Reviewed-by: Evan Green Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 6774da6435fa..b650a3a0ab7d 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -758,12 +758,12 @@ out_write_wakeup: static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) { - unsigned int m_irq_status; - unsigned int s_irq_status; - unsigned int geni_status; + u32 m_irq_en; + u32 m_irq_status; + u32 s_irq_status; + u32 geni_status; struct uart_port *uport = dev; unsigned long flags; - unsigned int m_irq_en; bool drop_rx = false; struct tty_port *tport = &uport->state->port; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); @@ -842,7 +842,7 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport) static int qcom_geni_serial_port_setup(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; + u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; u32 proto; if (uart_console(uport)) { @@ -941,14 +941,14 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, struct ktermios *termios, struct ktermios *old) { unsigned int baud; - unsigned int bits_per_char; - unsigned int tx_trans_cfg; - unsigned int tx_parity_cfg; - unsigned int rx_trans_cfg; - unsigned int rx_parity_cfg; - unsigned int stop_bit_len; + u32 bits_per_char; + u32 tx_trans_cfg; + u32 tx_parity_cfg; + u32 rx_trans_cfg; + u32 rx_parity_cfg; + u32 stop_bit_len; unsigned int clk_div; - unsigned long ser_clk_cfg; + u32 ser_clk_cfg; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); unsigned long clk_rate; -- cgit v1.2.3 From ad0d92d7ba6aecbe2705907c38ff8d8be4da1e9c Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Tue, 8 Jan 2019 12:00:16 +0000 Subject: dmaengine: imx-sdma: refine to load context only once The context loaded only one time before channel running,but currently sdma_config_channel() and dma_prep_* duplicated with sdma_load_context(), so refine it to load context only one time before channel running and reload after the channel terminated. Signed-off-by: Robin Gong Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index a2b0a0e71168..015c17a3b826 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -377,6 +377,7 @@ struct sdma_channel { unsigned long watermark_level; u32 shp_addr, per_addr; enum dma_status status; + bool context_loaded; struct imx_dma_data data; struct work_struct terminate_worker; }; @@ -970,6 +971,9 @@ static int sdma_load_context(struct sdma_channel *sdmac) int ret; unsigned long flags; + if (sdmac->context_loaded) + return 0; + if (sdmac->direction == DMA_DEV_TO_MEM) load_address = sdmac->pc_from_device; else if (sdmac->direction == DMA_DEV_TO_DEV) @@ -1012,6 +1016,8 @@ static int sdma_load_context(struct sdma_channel *sdmac) spin_unlock_irqrestore(&sdma->channel_0_lock, flags); + sdmac->context_loaded = true; + return ret; } @@ -1051,6 +1057,7 @@ static void sdma_channel_terminate_work(struct work_struct *work) sdmac->desc = NULL; spin_unlock_irqrestore(&sdmac->vc.lock, flags); vchan_dma_desc_free_list(&sdmac->vc, &head); + sdmac->context_loaded = false; } static int sdma_disable_channel_async(struct dma_chan *chan) -- cgit v1.2.3 From bdcb2c5d5ed0f100ae21decd30f0b2556b738b72 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 8 Jan 2019 17:57:55 +0200 Subject: dmaengine: dw-axi-dmac: Fix trivia typo Field name ststus_hi should be spelled as status_hi. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index f8888dc0b8dc..18b6014cf9b4 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -75,7 +75,7 @@ struct __packed axi_dma_lli { __le32 sstat; __le32 dstat; __le32 status_lo; - __le32 ststus_hi; + __le32 status_hi; __le32 reserved_lo; __le32 reserved_hi; }; -- cgit v1.2.3 From 9ac6cb5fbb1781d120ca0ad29d014d35c9c3f0c4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:17 +0100 Subject: i2c: add suspended flag and accessors for i2c adapters A few drivers open code the handling of suspended adapters. It could be handled by the core, though, to ensure generic handling. This patch adds the flag and accessor functions. The usage of these helpers is optional, though. See the kerneldoc in this patch. Using the new flag, we now reject further transfers if the adapter is already marked suspended. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 28460f6a60cc..926ca0a7477f 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1232,6 +1232,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) if (!adap->lock_ops) adap->lock_ops = &i2c_adapter_lock_ops; + adap->locked_flags = 0; rt_mutex_init(&adap->bus_lock); rt_mutex_init(&adap->mux_lock); mutex_init(&adap->userspace_clients_lock); @@ -1865,6 +1866,8 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (WARN_ON(!msgs || num < 1)) return -EINVAL; + if (WARN_ON(test_bit(I2C_ALF_IS_SUSPENDED, &adap->locked_flags))) + return -ESHUTDOWN; if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) return -EOPNOTSUPP; -- cgit v1.2.3 From 1adcc83e212c56afccdb633f5b3db020afbd0860 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:19 +0100 Subject: i2c: synquacer: remove unused is_suspended flag This flag was defined and checked but never set a value. Remove it. Signed-off-by: Wolfram Sang Acked-by: Ard Biesheuvel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-synquacer.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index 2184b7c3580e..d18b0941b71a 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -144,8 +144,6 @@ struct synquacer_i2c { u32 timeout_ms; enum i2c_state state; struct i2c_adapter adapter; - - bool is_suspended; }; static inline int is_lastmsg(struct synquacer_i2c *i2c) @@ -316,9 +314,6 @@ static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c, unsigned long timeout; int ret; - if (i2c->is_suspended) - return -EBUSY; - synquacer_i2c_hw_init(i2c); bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR); if (bsr & SYNQUACER_I2C_BSR_BB) { -- cgit v1.2.3 From f2e0d28cba1e049ccf8aa11fc30c3d7fb9ab8278 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:20 +0100 Subject: i2c: brcmstb: use core helper to mark adapter suspended Rejecting transfers should be handled by the core. Signed-off-by: Wolfram Sang Reviewed-by: Kamal Dasu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-brcmstb.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 826d32049996..f4d862234980 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -170,7 +170,6 @@ struct brcmstb_i2c_dev { struct bsc_regs *bsc_regmap; struct i2c_adapter adapter; struct completion done; - bool is_suspended; u32 clk_freq_hz; int data_regsz; }; @@ -467,9 +466,6 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter, int xfersz = brcmstb_i2c_get_xfersz(dev); u32 cond, cond_per_msg; - if (dev->is_suspended) - return -EBUSY; - /* Loop through all messages */ for (i = 0; i < num; i++) { pmsg = &msgs[i]; @@ -689,10 +685,7 @@ static int brcmstb_i2c_suspend(struct device *dev) { struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); - i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER); - i2c_dev->is_suspended = true; - i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER); - + i2c_mark_adapter_suspended(&i2c_dev->adapter); return 0; } @@ -700,10 +693,8 @@ static int brcmstb_i2c_resume(struct device *dev) { struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); - i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER); brcmstb_i2c_set_bsc_reg_defaults(i2c_dev); - i2c_dev->is_suspended = false; - i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER); + i2c_mark_adapter_resumed(&i2c_dev->adapter); return 0; } -- cgit v1.2.3 From 5601df355b63a8ddac21b2dfc3433d941a994c32 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:21 +0100 Subject: i2c: zx2967: use core helper to mark adapter suspended Rejecting transfers should be handled by the core. Also, this will ensure proper locking which was forgotten in this open coded version and make sure resume mark is set after enabling clocks (not before). Signed-off-by: Wolfram Sang Acked-by: Shawn Guo Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-zx2967.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-zx2967.c b/drivers/i2c/busses/i2c-zx2967.c index b8f9e020d80e..7b98d97da3c6 100644 --- a/drivers/i2c/busses/i2c-zx2967.c +++ b/drivers/i2c/busses/i2c-zx2967.c @@ -66,7 +66,6 @@ struct zx2967_i2c { int msg_rd; u8 *cur_trans; u8 access_cnt; - bool is_suspended; int error; }; @@ -313,9 +312,6 @@ static int zx2967_i2c_xfer(struct i2c_adapter *adap, int ret; int i; - if (i2c->is_suspended) - return -EBUSY; - zx2967_set_addr(i2c, msgs->addr); for (i = 0; i < num; i++) { @@ -470,7 +466,7 @@ static int __maybe_unused zx2967_i2c_suspend(struct device *dev) { struct zx2967_i2c *i2c = dev_get_drvdata(dev); - i2c->is_suspended = true; + i2c_mark_adapter_suspended(&i2c->adap); clk_disable_unprepare(i2c->clk); return 0; @@ -480,8 +476,8 @@ static int __maybe_unused zx2967_i2c_resume(struct device *dev) { struct zx2967_i2c *i2c = dev_get_drvdata(dev); - i2c->is_suspended = false; clk_prepare_enable(i2c->clk); + i2c_mark_adapter_resumed(&i2c->adap); return 0; } -- cgit v1.2.3 From 7b6b69984e0411daac4ba78c7dc6c6457c4aa5b4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:22 +0100 Subject: i2c: sprd: don't use pdev as variable name for struct device * The pointer to a device is usually named 'dev'. These 'pdev' here look much like copy&paste errors. Fix them to avoid confusion. Signed-off-by: Wolfram Sang Reviewed-by: Baolin Wang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sprd.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index a94e724f51dc..e266d8a713d9 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -586,40 +586,40 @@ static int sprd_i2c_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev) +static int __maybe_unused sprd_i2c_suspend_noirq(struct device *dev) { - struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); + struct sprd_i2c *i2c_dev = dev_get_drvdata(dev); i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); i2c_dev->is_suspended = true; i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); - return pm_runtime_force_suspend(pdev); + return pm_runtime_force_suspend(dev); } -static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev) +static int __maybe_unused sprd_i2c_resume_noirq(struct device *dev) { - struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); + struct sprd_i2c *i2c_dev = dev_get_drvdata(dev); i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); i2c_dev->is_suspended = false; i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); - return pm_runtime_force_resume(pdev); + return pm_runtime_force_resume(dev); } -static int __maybe_unused sprd_i2c_runtime_suspend(struct device *pdev) +static int __maybe_unused sprd_i2c_runtime_suspend(struct device *dev) { - struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); + struct sprd_i2c *i2c_dev = dev_get_drvdata(dev); clk_disable_unprepare(i2c_dev->clk); return 0; } -static int __maybe_unused sprd_i2c_runtime_resume(struct device *pdev) +static int __maybe_unused sprd_i2c_runtime_resume(struct device *dev) { - struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); + struct sprd_i2c *i2c_dev = dev_get_drvdata(dev); int ret; ret = clk_prepare_enable(i2c_dev->clk); -- cgit v1.2.3 From 5a7b81ff1b3e4493363c913e9f0affa904062798 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:23 +0100 Subject: i2c: sprd: use core helper to mark adapter suspended Rejecting transfers should be handled by the core. Signed-off-by: Wolfram Sang Reviewed-by: Baolin Wang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sprd.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index e266d8a713d9..961123529678 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -86,7 +86,6 @@ struct sprd_i2c { u32 count; int irq; int err; - bool is_suspended; }; static void sprd_i2c_set_count(struct sprd_i2c *i2c_dev, u32 count) @@ -284,9 +283,6 @@ static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct sprd_i2c *i2c_dev = i2c_adap->algo_data; int im, ret; - if (i2c_dev->is_suspended) - return -EBUSY; - ret = pm_runtime_get_sync(i2c_dev->dev); if (ret < 0) return ret; @@ -590,10 +586,7 @@ static int __maybe_unused sprd_i2c_suspend_noirq(struct device *dev) { struct sprd_i2c *i2c_dev = dev_get_drvdata(dev); - i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); - i2c_dev->is_suspended = true; - i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); - + i2c_mark_adapter_suspended(&i2c_dev->adap); return pm_runtime_force_suspend(dev); } @@ -601,10 +594,7 @@ static int __maybe_unused sprd_i2c_resume_noirq(struct device *dev) { struct sprd_i2c *i2c_dev = dev_get_drvdata(dev); - i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); - i2c_dev->is_suspended = false; - i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); - + i2c_mark_adapter_resumed(&i2c_dev->adap); return pm_runtime_force_resume(dev); } -- cgit v1.2.3 From d5c95bd6f3254e23736c48ff8f6c69c470b910a4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:24 +0100 Subject: i2c: exynos5: use core helper to mark adapter suspended Rejecting transfers should be handled by the core. Also, this will ensure proper locking which was forgotten in this open coded version. Signed-off-by: Wolfram Sang Tested-by: Marek Szyprowski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index c1ce2299a76e..41de4ee409b6 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -183,7 +183,6 @@ enum i2c_type_exynos { struct exynos5_i2c { struct i2c_adapter adap; - unsigned int suspended:1; struct i2c_msg *msg; struct completion msg_complete; @@ -715,11 +714,6 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, struct exynos5_i2c *i2c = adap->algo_data; int i, ret; - if (i2c->suspended) { - dev_err(i2c->dev, "HS-I2C is not initialized.\n"); - return -EIO; - } - ret = clk_enable(i2c->clk); if (ret) return ret; @@ -847,8 +841,7 @@ static int exynos5_i2c_suspend_noirq(struct device *dev) { struct exynos5_i2c *i2c = dev_get_drvdata(dev); - i2c->suspended = 1; - + i2c_mark_adapter_suspended(&i2c->adap); clk_unprepare(i2c->clk); return 0; @@ -871,7 +864,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev) exynos5_i2c_init(i2c); clk_disable(i2c->clk); - i2c->suspended = 0; + i2c_mark_adapter_resumed(&i2c->adap); return 0; } -- cgit v1.2.3 From 2088716f90d160e735a469b8e1d0653facd74f16 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:25 +0100 Subject: i2c: s3c2410: use core helper to mark adapter suspended Rejecting transfers should be handled by the core. Also, this will ensure proper locking which was forgotten in this open coded version. Signed-off-by: Wolfram Sang Tested-by: Marek Szyprowski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 2f2e28d60ef5..53bc021f4a5a 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -104,7 +104,6 @@ enum s3c24xx_i2c_state { struct s3c24xx_i2c { wait_queue_head_t wait; kernel_ulong_t quirks; - unsigned int suspended:1; struct i2c_msg *msg; unsigned int msg_num; @@ -703,9 +702,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, unsigned long timeout; int ret; - if (i2c->suspended) - return -EIO; - ret = s3c24xx_i2c_set_master(i2c); if (ret != 0) { dev_err(i2c->dev, "cannot get bus (error %d)\n", ret); @@ -1246,7 +1242,7 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev) { struct s3c24xx_i2c *i2c = dev_get_drvdata(dev); - i2c->suspended = 1; + i2c_mark_adapter_suspended(&i2c->adap); if (!IS_ERR(i2c->sysreg)) regmap_read(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, &i2c->sys_i2c_cfg); @@ -1267,7 +1263,7 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev) return ret; s3c24xx_i2c_init(i2c); clk_disable(i2c->clk); - i2c->suspended = 0; + i2c_mark_adapter_resumed(&i2c->adap); return 0; } -- cgit v1.2.3 From 18569fa89a4db9ed6b5181624788a1574a9b6ed7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 19 Dec 2018 17:48:26 +0100 Subject: i2c: rcar: add suspend/resume support Because the adapter will be set up before every transaction anyhow, we just need to mark it as suspended to the I2C core. Signed-off-by: Hiromitsu Yamasaki Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 254e6219e538..1d6390eed861 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1017,10 +1017,35 @@ static int rcar_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int rcar_i2c_suspend(struct device *dev) +{ + struct rcar_i2c_priv *priv = dev_get_drvdata(dev); + + i2c_mark_adapter_suspended(&priv->adap); + return 0; +} + +static int rcar_i2c_resume(struct device *dev) +{ + struct rcar_i2c_priv *priv = dev_get_drvdata(dev); + + i2c_mark_adapter_resumed(&priv->adap); + return 0; +} + +static SIMPLE_DEV_PM_OPS(rcar_i2c_pm_ops, rcar_i2c_suspend, rcar_i2c_resume); + +#define DEV_PM_OPS (&rcar_i2c_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct platform_driver rcar_i2c_driver = { .driver = { .name = "i2c-rcar", .of_match_table = rcar_i2c_dt_ids, + .pm = DEV_PM_OPS, }, .probe = rcar_i2c_probe, .remove = rcar_i2c_remove, -- cgit v1.2.3 From e181a569d8e52d5a5c91cf2ddc3ebcfb81163887 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Tue, 4 Dec 2018 11:20:27 +0000 Subject: soc: fsl: dpio: cleanup the cpu array on dpaa2_io_down The dpio_by_cpu array should not contain a reference to a freed dpaa2_io object. This patch adds the necessary cleanup in dpaa2_io_down. Signed-off-by: Ioana Ciornei Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-service.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index ec0837ff039a..ab046f241d32 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -160,6 +160,11 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc) */ void dpaa2_io_down(struct dpaa2_io *d) { + spin_lock(&dpio_list_lock); + dpio_by_cpu[d->dpio_desc.cpu] = NULL; + list_del(&d->node); + spin_unlock(&dpio_list_lock); + kfree(d); } -- cgit v1.2.3 From 991e873223e9bcfaf10a0074eec1507c1ddfb6ab Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Tue, 4 Dec 2018 11:20:29 +0000 Subject: soc: fsl: dpio: use a cpumask to identify which cpus are unused The current implementation of the dpio driver uses a static next_cpu variable to keep track of the index of the next cpu available. This approach does not handle well unbinding and binding dpio devices in a random order. For example, unbinding a dpio and then binding it again with the driver, will generate the below error: $ echo dpio.5 > /sys/bus/fsl-mc/drivers/fsl_mc_dpio/unbind $ echo dpio.5 > /sys/bus/fsl-mc/drivers/fsl_mc_dpio/bind [ 103.946380] fsl_mc_dpio dpio.5: probe failed. Number of DPIOs exceeds NR_CPUS. [ 103.955157] fsl_mc_dpio dpio.5: fsl_mc_driver_probe failed: -34 -bash: echo: write error: No such device Fix this error by keeping a global cpumask of unused cpus that will be updated at every dpaa2_dpio_[probe,remove]. Signed-off-by: Ioana Ciornei Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-driver.c | 25 ++++++++++++++++--------- drivers/soc/fsl/dpio/dpio-service.c | 13 +++++++++++++ 2 files changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index e58fcc9096e8..832175cac739 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -30,6 +30,8 @@ struct dpio_priv { struct dpaa2_io *io; }; +static cpumask_var_t cpus_unused_mask; + static irqreturn_t dpio_irq_handler(int irq_num, void *arg) { struct device *dev = (struct device *)arg; @@ -86,7 +88,7 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) struct dpio_priv *priv; int err = -ENOMEM; struct device *dev = &dpio_dev->dev; - static int next_cpu = -1; + int possible_next_cpu; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -128,17 +130,14 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) desc.dpio_id = dpio_dev->obj_desc.id; /* get the cpu to use for the affinity hint */ - if (next_cpu == -1) - next_cpu = cpumask_first(cpu_online_mask); - else - next_cpu = cpumask_next(next_cpu, cpu_online_mask); - - if (!cpu_possible(next_cpu)) { + possible_next_cpu = cpumask_first(cpus_unused_mask); + if (possible_next_cpu >= nr_cpu_ids) { dev_err(dev, "probe failed. Number of DPIOs exceeds NR_CPUS.\n"); err = -ERANGE; goto err_allocate_irqs; } - desc.cpu = next_cpu; + desc.cpu = possible_next_cpu; + cpumask_clear_cpu(possible_next_cpu, cpus_unused_mask); /* * Set the CENA regs to be the cache inhibited area of the portal to @@ -211,7 +210,7 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) { struct device *dev; struct dpio_priv *priv; - int err; + int err = 0, cpu; dev = &dpio_dev->dev; priv = dev_get_drvdata(dev); @@ -220,6 +219,9 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) dpio_teardown_irqs(dpio_dev); + cpu = dpaa2_io_get_cpu(priv->io); + cpumask_set_cpu(cpu, cpus_unused_mask); + err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io); if (err) { dev_err(dev, "MC portal allocation failed\n"); @@ -267,11 +269,16 @@ static struct fsl_mc_driver dpaa2_dpio_driver = { static int dpio_driver_init(void) { + if (!zalloc_cpumask_var(&cpus_unused_mask, GFP_KERNEL)) + return -ENOMEM; + cpumask_copy(cpus_unused_mask, cpu_online_mask); + return fsl_mc_driver_register(&dpaa2_dpio_driver); } static void dpio_driver_exit(void) { + free_cpumask_var(cpus_unused_mask); fsl_mc_driver_unregister(&dpaa2_dpio_driver); } module_init(dpio_driver_init); diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index ab046f241d32..c02bfb18a1f0 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -214,6 +214,19 @@ done: return IRQ_HANDLED; } +/** + * dpaa2_io_get_cpu() - get the cpu associated with a given DPIO object + * + * @d: the given DPIO object. + * + * Return the cpu associated with the DPIO object + */ +int dpaa2_io_get_cpu(struct dpaa2_io *d) +{ + return d->dpio_desc.cpu; +} +EXPORT_SYMBOL(dpaa2_io_get_cpu); + /** * dpaa2_io_service_register() - Prepare for servicing of FQDAN or CDAN * notifications on the given DPIO service. -- cgit v1.2.3 From 7a7b0fea6f848d0a73ee6defe6b9d192af2dda3a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 10:08:05 -0600 Subject: IB/srp: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Bart Van Assche Signed-off-by: Jason Gunthorpe --- drivers/infiniband/ulp/srp/ib_srp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 31d91538bbf4..0f855294ff3f 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -443,8 +443,7 @@ static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, if (pool_size <= 0) goto err; ret = -ENOMEM; - pool = kzalloc(sizeof(struct srp_fr_pool) + - pool_size * sizeof(struct srp_fr_desc), GFP_KERNEL); + pool = kzalloc(struct_size(pool, desc, pool_size), GFP_KERNEL); if (!pool) goto err; pool->size = pool_size; -- cgit v1.2.3 From 96f87ee1811306d0c8cf94b8c37b0e4f725b01d1 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 8 Jan 2019 16:07:23 +0200 Subject: RDMA: Clean structures from CONFIG_INFINIBAND_ON_DEMAND_PAGING CONFIG_INFINIBAND_ON_DEMAND_PAGING is used in general structures to micro-optimize the memory footprint. Remove it, so it will allow us to simplify various ODP device flows. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index b06d3b1efea8..93c288a4de2b 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -911,7 +911,6 @@ struct mlx5_ib_dev { /* Prevents soft lock on massive reg MRs */ struct mutex slow_path_mutex; int fill_delay; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING struct ib_odp_caps odp_caps; u64 odp_max_size; struct mlx5_ib_pf_eq odp_pf_eq; @@ -923,7 +922,6 @@ struct mlx5_ib_dev { struct srcu_struct mr_srcu; u32 null_mkey; struct workqueue_struct *advise_mr_wq; -#endif struct mlx5_ib_flow_db *flow_db; /* protect resources needed as part of reset flow */ spinlock_t reset_flow_resource_lock; -- cgit v1.2.3 From e502b8b011294c293064ef1baeb04235ccc05439 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 8 Jan 2019 16:07:24 +0200 Subject: RDMA/core: Don't depend device ODP capabilities on kconfig option Device capability bits are exposing what specific device supports from HW perspective. Those bits are not dependent on kernel configurations and RDMA/core should ensure that proper interfaces to users will be disabled if CONFIG_INFINIBAND_ON_DEMAND_PAGING is not set. Fixes: f4056bfd8ccf ("IB/core: Add on demand paging caps to ib_uverbs_ex_query_device") Fixes: 8cdd312cfed7 ("IB/mlx5: Implement the ODP capability query verb") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 2 -- drivers/infiniband/hw/mlx5/main.c | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 6b12cc5f97b2..549d9eedf62e 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -3609,7 +3609,6 @@ static int ib_uverbs_ex_query_device(struct uverbs_attr_bundle *attrs) copy_query_dev_fields(ucontext, &resp.base, &attr); -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING resp.odp_caps.general_caps = attr.odp_caps.general_caps; resp.odp_caps.per_transport_caps.rc_odp_caps = attr.odp_caps.per_transport_caps.rc_odp_caps; @@ -3617,7 +3616,6 @@ static int ib_uverbs_ex_query_device(struct uverbs_attr_bundle *attrs) attr.odp_caps.per_transport_caps.uc_odp_caps; resp.odp_caps.per_transport_caps.ud_odp_caps = attr.odp_caps.per_transport_caps.ud_odp_caps; -#endif resp.timestamp_mask = attr.timestamp_mask; resp.hca_core_clock = attr.hca_core_clock; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 94fe253d4956..06ee1f0cb22d 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -923,11 +923,11 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->hca_core_clock = MLX5_CAP_GEN(mdev, device_frequency_khz); props->timestamp_mask = 0x7FFFFFFFFFFFFFFFULL; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - if (MLX5_CAP_GEN(mdev, pg)) - props->device_cap_flags |= IB_DEVICE_ON_DEMAND_PAGING; - props->odp_caps = dev->odp_caps; -#endif + if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) { + if (MLX5_CAP_GEN(mdev, pg)) + props->device_cap_flags |= IB_DEVICE_ON_DEMAND_PAGING; + props->odp_caps = dev->odp_caps; + } if (MLX5_CAP_GEN(mdev, cd)) props->device_cap_flags |= IB_DEVICE_CROSS_CHANNEL; -- cgit v1.2.3 From 8b4d5bc5cf3f813dc4df5d69c2fcde16c40d8abd Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 8 Jan 2019 16:07:25 +0200 Subject: RDMA/mlx5: Introduce and reuse helper to identify ODP MR Consolidate various checks if MR is ODP backed to one simple helper and update call sites to use it. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/mlx5_ib.h | 10 ++++++++++ drivers/infiniband/hw/mlx5/mr.c | 13 +++---------- drivers/infiniband/hw/mlx5/odp.c | 6 +++--- 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 93c288a4de2b..81efa5def8ad 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -589,6 +590,12 @@ struct mlx5_ib_mr { wait_queue_head_t q_leaf_free; }; +static inline bool is_odp_mr(struct mlx5_ib_mr *mr) +{ + return IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING) && mr->umem && + mr->umem->is_odp; +} + struct mlx5_ib_mw { struct ib_mw ibmw; struct mlx5_core_mkey mmkey; @@ -1213,6 +1220,9 @@ mlx5_ib_advise_mr_prefetch(struct ib_pd *pd, { return -EOPNOTSUPP; } +static inline void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, + unsigned long start, + unsigned long end){}; #endif /* CONFIG_INFINIBAND_ON_DEMAND_PAGING */ /* Needed for rep profile */ diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index fd6ea1f75085..c389750f771e 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -95,10 +95,9 @@ static bool use_umr_mtt_update(struct mlx5_ib_mr *mr, u64 start, u64 length) length + (start & (MLX5_ADAPTER_PAGE_SIZE - 1)); } -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING static void update_odp_mr(struct mlx5_ib_mr *mr) { - if (mr->umem->is_odp) { + if (is_odp_mr(mr)) { /* * This barrier prevents the compiler from moving the * setting of umem->odp_data->private to point to our @@ -121,7 +120,6 @@ static void update_odp_mr(struct mlx5_ib_mr *mr) smp_wmb(); } } -#endif static void reg_mr_callback(int status, void *context) { @@ -1386,9 +1384,7 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, mr->umem = umem; set_mr_fields(dev, mr, npages, length, access_flags); -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING update_odp_mr(mr); -#endif if (!populate_mtts) { int update_xlt_flags = MLX5_IB_UPD_XLT_ENABLE; @@ -1553,9 +1549,7 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start, set_mr_fields(dev, mr, npages, len, access_flags); -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING update_odp_mr(mr); -#endif return 0; err: @@ -1641,8 +1635,7 @@ static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) int npages = mr->npages; struct ib_umem *umem = mr->umem; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - if (umem && umem->is_odp) { + if (is_odp_mr(mr)) { struct ib_umem_odp *umem_odp = to_ib_umem_odp(umem); /* Prevent new page faults from succeeding */ @@ -1666,7 +1659,7 @@ static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) /* Avoid double-freeing the umem. */ umem = NULL; } -#endif + clean_mr(dev, mr); /* diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index 01e0f6200631..37d6653f9636 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -103,7 +103,7 @@ static int check_parent(struct ib_umem_odp *odp, struct ib_ucontext_per_mm *mr_to_per_mm(struct mlx5_ib_mr *mr) { - if (WARN_ON(!mr || !mr->umem || !mr->umem->is_odp)) + if (WARN_ON(!mr || !is_odp_mr(mr))) return NULL; return to_ib_umem_odp(mr->umem)->per_mm; @@ -739,12 +739,12 @@ next_mr: goto srcu_unlock; } - if (prefetch && !mr->umem->is_odp) { + if (prefetch && !is_odp_mr(mr)) { ret = -EINVAL; goto srcu_unlock; } - if (!mr->umem->is_odp) { + if (!is_odp_mr(mr)) { mlx5_ib_dbg(dev, "skipping non ODP MR (lkey=0x%06x) in page fault handler.\n", key); if (bytes_mapped) -- cgit v1.2.3 From 13859d5df418ea535926e2b57c29d5161c522b9d Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 8 Jan 2019 16:07:26 +0200 Subject: RDMA/mlx5: Embed into the code flow the ODP config option Convert various places to more readable code, which embeds CONFIG_INFINIBAND_ON_DEMAND_PAGING into the code flow. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 3 --- drivers/infiniband/hw/mlx5/main.c | 41 ++++++++++++++++++------------------ drivers/infiniband/hw/mlx5/mem.c | 5 +---- drivers/infiniband/hw/mlx5/mr.c | 28 +++++++++++------------- 4 files changed, 33 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 549d9eedf62e..d4f1a2ef5015 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -234,14 +234,11 @@ static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs) ucontext->closing = false; ucontext->cleanup_retryable = false; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING mutex_init(&ucontext->per_mm_list_lock); INIT_LIST_HEAD(&ucontext->per_mm_list); if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_ON_DEMAND_PAGING)) ucontext->invalidate_range = NULL; -#endif - resp.num_comp_vectors = file->device->num_comp_vectors; ret = get_unused_fd_flags(O_CLOEXEC); diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 06ee1f0cb22d..11e9783cefcc 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1763,9 +1763,9 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, if (err) goto out_sys_pages; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - context->ibucontext.invalidate_range = &mlx5_ib_invalidate_range; -#endif + if (ibdev->attrs.device_cap_flags & IB_DEVICE_ON_DEMAND_PAGING) + context->ibucontext.invalidate_range = + &mlx5_ib_invalidate_range; if (req.flags & MLX5_IB_ALLOC_UCTX_DEVX) { err = mlx5_ib_devx_create(dev, true); @@ -1897,12 +1897,10 @@ static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) struct mlx5_ib_dev *dev = to_mdev(ibcontext->device); struct mlx5_bfreg_info *bfregi; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING /* All umem's must be destroyed before destroying the ucontext. */ mutex_lock(&ibcontext->per_mm_list_lock); WARN_ON(!list_empty(&ibcontext->per_mm_list)); mutex_unlock(&ibcontext->per_mm_list_lock); -#endif bfregi = &context->bfregi; mlx5_ib_dealloc_transport_domain(dev, context->tdn, context->devx_uid); @@ -5722,11 +5720,11 @@ static struct ib_counters *mlx5_ib_create_counters(struct ib_device *device, void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev) { mlx5_ib_cleanup_multiport_master(dev); -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - cleanup_srcu_struct(&dev->mr_srcu); - drain_workqueue(dev->advise_mr_wq); - destroy_workqueue(dev->advise_mr_wq); -#endif + if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) { + cleanup_srcu_struct(&dev->mr_srcu); + drain_workqueue(dev->advise_mr_wq); + destroy_workqueue(dev->advise_mr_wq); + } kfree(dev->port); } @@ -5779,19 +5777,20 @@ int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev) spin_lock_init(&dev->memic.memic_lock); dev->memic.dev = mdev; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - dev->advise_mr_wq = alloc_ordered_workqueue("mlx5_ib_advise_mr_wq", 0); - if (!dev->advise_mr_wq) { - err = -ENOMEM; - goto err_mp; - } + if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) { + dev->advise_mr_wq = + alloc_ordered_workqueue("mlx5_ib_advise_mr_wq", 0); + if (!dev->advise_mr_wq) { + err = -ENOMEM; + goto err_mp; + } - err = init_srcu_struct(&dev->mr_srcu); - if (err) { - destroy_workqueue(dev->advise_mr_wq); - goto err_mp; + err = init_srcu_struct(&dev->mr_srcu); + if (err) { + destroy_workqueue(dev->advise_mr_wq); + goto err_mp; + } } -#endif return 0; err_mp: diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c index 549234988bb4..9f90be296ee0 100644 --- a/drivers/infiniband/hw/mlx5/mem.c +++ b/drivers/infiniband/hw/mlx5/mem.c @@ -111,7 +111,6 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, *count = i; } -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING static u64 umem_dma_to_mtt(dma_addr_t umem_dma) { u64 mtt_entry = umem_dma & ODP_DMA_ADDR_MASK; @@ -123,7 +122,6 @@ static u64 umem_dma_to_mtt(dma_addr_t umem_dma) return mtt_entry; } -#endif /* * Populate the given array with bus addresses from the umem. @@ -151,7 +149,7 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, int len; struct scatterlist *sg; int entry; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING + if (umem->is_odp) { WARN_ON(shift != 0); WARN_ON(access_flags != (MLX5_IB_MTT_READ | MLX5_IB_MTT_WRITE)); @@ -164,7 +162,6 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, } return; } -#endif i = 0; for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) { diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index c389750f771e..494a90f4348c 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -71,10 +71,9 @@ static int destroy_mkey(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) { int err = mlx5_core_destroy_mkey(dev->mdev, &mr->mmkey); -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - /* Wait until all page fault handlers using the mr complete. */ - synchronize_srcu(&dev->mr_srcu); -#endif + if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) + /* Wait until all page fault handlers using the mr complete. */ + synchronize_srcu(&dev->mr_srcu); return err; } @@ -254,9 +253,8 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num) mlx5_core_destroy_mkey(dev->mdev, &mr->mmkey); } -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - synchronize_srcu(&dev->mr_srcu); -#endif + if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) + synchronize_srcu(&dev->mr_srcu); list_for_each_entry_safe(mr, tmp_mr, &del_list, list) { list_del(&mr->list); @@ -1329,8 +1327,8 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, mlx5_ib_dbg(dev, "start 0x%llx, virt_addr 0x%llx, length 0x%llx, access_flags 0x%x\n", start, virt_addr, length, access_flags); -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - if (!start && length == U64_MAX) { + if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING) && !start && + length == U64_MAX) { if (!(access_flags & IB_ACCESS_ON_DEMAND) || !(dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT)) return ERR_PTR(-EINVAL); @@ -1340,7 +1338,6 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return ERR_CAST(mr); return &mr->ibmr; } -#endif err = mr_umem_get(pd, start, length, access_flags, &umem, &npages, &page_shift, &ncont, &order); @@ -1401,9 +1398,9 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, } } -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - mr->live = 1; -#endif + if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) + mr->live = 1; + return &mr->ibmr; error: ib_umem_release(umem); @@ -1518,9 +1515,8 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start, } mr->allocated_from_cache = 0; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - mr->live = 1; -#endif + if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) + mr->live = 1; } else { /* * Send a UMR WQE -- cgit v1.2.3 From 9f475ebff8e437ccccb3cf0259b5de7540f413be Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:18 +0100 Subject: scsi: gdth: refactor ioc_general This function is a huge mess with duplicated error handling. Split out a few useful helpers and use goto labels to untangle the error handling and no-data ioctl handling. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth.c | 250 +++++++++++++++++++++++++++------------------------- 1 file changed, 132 insertions(+), 118 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 194c294f9b6c..dd6784e03a57 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -4155,131 +4155,145 @@ static int ioc_resetdrv(void __user *arg, char *cmnd) return 0; } -static int ioc_general(void __user *arg, char *cmnd) +static void gdth_ioc_cacheservice(gdth_ha_str *ha, gdth_ioctl_general *gen, + u64 paddr) { - gdth_ioctl_general gen; - char *buf = NULL; - u64 paddr; - gdth_ha_str *ha; - int rval; + if (ha->cache_feat & GDT_64BIT) { + /* copy elements from 32-bit IOCTL structure */ + gen->command.u.cache64.BlockCnt = gen->command.u.cache.BlockCnt; + gen->command.u.cache64.BlockNo = gen->command.u.cache.BlockNo; + gen->command.u.cache64.DeviceNo = gen->command.u.cache.DeviceNo; + + if (ha->cache_feat & SCATTER_GATHER) { + gen->command.u.cache64.DestAddr = (u64)-1; + gen->command.u.cache64.sg_canz = 1; + gen->command.u.cache64.sg_lst[0].sg_ptr = paddr; + gen->command.u.cache64.sg_lst[0].sg_len = gen->data_len; + gen->command.u.cache64.sg_lst[1].sg_len = 0; + } else { + gen->command.u.cache64.DestAddr = paddr; + gen->command.u.cache64.sg_canz = 0; + } + } else { + if (ha->cache_feat & SCATTER_GATHER) { + gen->command.u.cache.DestAddr = 0xffffffff; + gen->command.u.cache.sg_canz = 1; + gen->command.u.cache.sg_lst[0].sg_ptr = (u32)paddr; + gen->command.u.cache.sg_lst[0].sg_len = gen->data_len; + gen->command.u.cache.sg_lst[1].sg_len = 0; + } else { + gen->command.u.cache.DestAddr = paddr; + gen->command.u.cache.sg_canz = 0; + } + } +} - if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general))) - return -EFAULT; - ha = gdth_find_ha(gen.ionode); - if (!ha) - return -EFAULT; +static void gdth_ioc_scsiraw(gdth_ha_str *ha, gdth_ioctl_general *gen, + u64 paddr) +{ + if (ha->raw_feat & GDT_64BIT) { + /* copy elements from 32-bit IOCTL structure */ + char cmd[16]; + + gen->command.u.raw64.sense_len = gen->command.u.raw.sense_len; + gen->command.u.raw64.bus = gen->command.u.raw.bus; + gen->command.u.raw64.lun = gen->command.u.raw.lun; + gen->command.u.raw64.target = gen->command.u.raw.target; + memcpy(cmd, gen->command.u.raw.cmd, 16); + memcpy(gen->command.u.raw64.cmd, cmd, 16); + gen->command.u.raw64.clen = gen->command.u.raw.clen; + gen->command.u.raw64.sdlen = gen->command.u.raw.sdlen; + gen->command.u.raw64.direction = gen->command.u.raw.direction; + + /* addresses */ + if (ha->raw_feat & SCATTER_GATHER) { + gen->command.u.raw64.sdata = (u64)-1; + gen->command.u.raw64.sg_ranz = 1; + gen->command.u.raw64.sg_lst[0].sg_ptr = paddr; + gen->command.u.raw64.sg_lst[0].sg_len = gen->data_len; + gen->command.u.raw64.sg_lst[1].sg_len = 0; + } else { + gen->command.u.raw64.sdata = paddr; + gen->command.u.raw64.sg_ranz = 0; + } - if (gen.data_len > INT_MAX) - return -EINVAL; - if (gen.sense_len > INT_MAX) - return -EINVAL; - if (gen.data_len + gen.sense_len > INT_MAX) - return -EINVAL; + gen->command.u.raw64.sense_data = paddr + gen->data_len; + } else { + if (ha->raw_feat & SCATTER_GATHER) { + gen->command.u.raw.sdata = 0xffffffff; + gen->command.u.raw.sg_ranz = 1; + gen->command.u.raw.sg_lst[0].sg_ptr = (u32)paddr; + gen->command.u.raw.sg_lst[0].sg_len = gen->data_len; + gen->command.u.raw.sg_lst[1].sg_len = 0; + } else { + gen->command.u.raw.sdata = paddr; + gen->command.u.raw.sg_ranz = 0; + } - if (gen.data_len + gen.sense_len != 0) { - if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len, - FALSE, &paddr))) - return -EFAULT; - if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general), - gen.data_len + gen.sense_len)) { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return -EFAULT; - } + gen->command.u.raw.sense_data = (u32)paddr + gen->data_len; + } +} - if (gen.command.OpCode == GDT_IOCTL) { - gen.command.u.ioctl.p_param = paddr; - } else if (gen.command.Service == CACHESERVICE) { - if (ha->cache_feat & GDT_64BIT) { - /* copy elements from 32-bit IOCTL structure */ - gen.command.u.cache64.BlockCnt = gen.command.u.cache.BlockCnt; - gen.command.u.cache64.BlockNo = gen.command.u.cache.BlockNo; - gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo; - /* addresses */ - if (ha->cache_feat & SCATTER_GATHER) { - gen.command.u.cache64.DestAddr = (u64)-1; - gen.command.u.cache64.sg_canz = 1; - gen.command.u.cache64.sg_lst[0].sg_ptr = paddr; - gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len; - gen.command.u.cache64.sg_lst[1].sg_len = 0; - } else { - gen.command.u.cache64.DestAddr = paddr; - gen.command.u.cache64.sg_canz = 0; - } - } else { - if (ha->cache_feat & SCATTER_GATHER) { - gen.command.u.cache.DestAddr = 0xffffffff; - gen.command.u.cache.sg_canz = 1; - gen.command.u.cache.sg_lst[0].sg_ptr = (u32)paddr; - gen.command.u.cache.sg_lst[0].sg_len = gen.data_len; - gen.command.u.cache.sg_lst[1].sg_len = 0; - } else { - gen.command.u.cache.DestAddr = paddr; - gen.command.u.cache.sg_canz = 0; - } - } - } else if (gen.command.Service == SCSIRAWSERVICE) { - if (ha->raw_feat & GDT_64BIT) { - /* copy elements from 32-bit IOCTL structure */ - char cmd[16]; - gen.command.u.raw64.sense_len = gen.command.u.raw.sense_len; - gen.command.u.raw64.bus = gen.command.u.raw.bus; - gen.command.u.raw64.lun = gen.command.u.raw.lun; - gen.command.u.raw64.target = gen.command.u.raw.target; - memcpy(cmd, gen.command.u.raw.cmd, 16); - memcpy(gen.command.u.raw64.cmd, cmd, 16); - gen.command.u.raw64.clen = gen.command.u.raw.clen; - gen.command.u.raw64.sdlen = gen.command.u.raw.sdlen; - gen.command.u.raw64.direction = gen.command.u.raw.direction; - /* addresses */ - if (ha->raw_feat & SCATTER_GATHER) { - gen.command.u.raw64.sdata = (u64)-1; - gen.command.u.raw64.sg_ranz = 1; - gen.command.u.raw64.sg_lst[0].sg_ptr = paddr; - gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len; - gen.command.u.raw64.sg_lst[1].sg_len = 0; - } else { - gen.command.u.raw64.sdata = paddr; - gen.command.u.raw64.sg_ranz = 0; - } - gen.command.u.raw64.sense_data = paddr + gen.data_len; - } else { - if (ha->raw_feat & SCATTER_GATHER) { - gen.command.u.raw.sdata = 0xffffffff; - gen.command.u.raw.sg_ranz = 1; - gen.command.u.raw.sg_lst[0].sg_ptr = (u32)paddr; - gen.command.u.raw.sg_lst[0].sg_len = gen.data_len; - gen.command.u.raw.sg_lst[1].sg_len = 0; - } else { - gen.command.u.raw.sdata = paddr; - gen.command.u.raw.sg_ranz = 0; - } - gen.command.u.raw.sense_data = (u32)paddr + gen.data_len; - } - } else { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return -EFAULT; - } - } +static int ioc_general(void __user *arg, char *cmnd) +{ + gdth_ioctl_general gen; + gdth_ha_str *ha; + char *buf = NULL; + u64 paddr; + int rval; + + if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general))) + return -EFAULT; + ha = gdth_find_ha(gen.ionode); + if (!ha) + return -EFAULT; + + if (gen.data_len > INT_MAX) + return -EINVAL; + if (gen.sense_len > INT_MAX) + return -EINVAL; + if (gen.data_len + gen.sense_len > INT_MAX) + return -EINVAL; + + if (gen.data_len + gen.sense_len > 0) { + buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len, FALSE, + &paddr); + if (!buf) + return -EFAULT; + + rval = -EFAULT; + if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general), + gen.data_len + gen.sense_len)) + goto out_free_buf; + + if (gen.command.OpCode == GDT_IOCTL) + gen.command.u.ioctl.p_param = paddr; + else if (gen.command.Service == CACHESERVICE) + gdth_ioc_cacheservice(ha, &gen, paddr); + else if (gen.command.Service == SCSIRAWSERVICE) + gdth_ioc_scsiraw(ha, &gen, paddr); + else + goto out_free_buf; + } - rval = __gdth_execute(ha->sdev, &gen.command, cmnd, gen.timeout, &gen.info); - if (rval < 0) { + rval = __gdth_execute(ha->sdev, &gen.command, cmnd, gen.timeout, + &gen.info); + if (rval < 0) + goto out_free_buf; + gen.status = rval; + + rval = -EFAULT; + if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf, + gen.data_len + gen.sense_len)) + goto out_free_buf; + if (copy_to_user(arg, &gen, + sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) + goto out_free_buf; + + rval = 0; +out_free_buf: gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return rval; - } - gen.status = rval; - - if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf, - gen.data_len + gen.sense_len)) { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return -EFAULT; - } - if (copy_to_user(arg, &gen, - sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return -EFAULT; - } - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return 0; + return rval; } static int ioc_hdrlist(void __user *arg, char *cmnd) -- cgit v1.2.3 From 8d22022c3a56314b182810794cae47686b765313 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:19 +0100 Subject: scsi: gdth: reuse dma coherent allocation in gdth_show_info gdth_show_info currently allocs and frees a dma buffer four times which isn't very efficient. Reuse a single allocation instead. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth_proc.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 3a9751a80225..bd5532a80b0e 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -226,11 +226,13 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) #endif if (ha->more_proc) { + size_t size = max_t(size_t, GDTH_SCRATCH, sizeof(gdth_hget_str)); + /* more information: 2. about physical devices */ seq_puts(m, "\nPhysical Devices:"); flag = FALSE; - buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); + buf = gdth_ioctl_alloc(ha, size, FALSE, &paddr); if (!buf) goto stop_output; for (i = 0; i < ha->bus_cnt; ++i) { @@ -323,7 +325,6 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) } } } - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); if (!flag) seq_puts(m, "\n --\n"); @@ -332,9 +333,6 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) seq_puts(m, "\nLogical Drives:"); flag = FALSE; - buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); - if (!buf) - goto stop_output; for (i = 0; i < MAX_LDRIVES; ++i) { if (!ha->hdr[i].is_logdrv) continue; @@ -408,7 +406,6 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) seq_printf(m, " To Array Drv.:\t%s\n", hrec); } - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); if (!flag) seq_puts(m, "\n --\n"); @@ -417,9 +414,6 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) seq_puts(m, "\nArray Drives:"); flag = FALSE; - buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); - if (!buf) - goto stop_output; for (i = 0; i < MAX_LDRIVES; ++i) { if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master)) continue; @@ -468,8 +462,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) hrec); } } - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); - + if (!flag) seq_puts(m, "\n --\n"); @@ -477,9 +470,6 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) seq_puts(m, "\nHost Drives:"); flag = FALSE; - buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr); - if (!buf) - goto stop_output; for (i = 0; i < MAX_LDRIVES; ++i) { if (!ha->hdr[i].is_logdrv || (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master)) @@ -510,7 +500,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) } } } - gdth_ioctl_free(ha, sizeof(gdth_hget_str), buf, paddr); + gdth_ioctl_free(ha, size, buf, paddr); for (i = 0; i < MAX_HDRIVES; ++i) { if (!(ha->hdr[i].present)) -- cgit v1.2.3 From 463563fa745ac7ac564458c1903325b937ee8c5f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:20 +0100 Subject: scsi: gdth: remove gdth_{alloc,free}_ioctl Out of the three callers once insists on the scratch buffer, and the others are fine with a new allocation. Switch those two to just use pci_alloc_consistent directly, and open code the scratch buffer allocation in the remaining one. This avoids a case where we might be doing a memory allocation under a spinlock with irqs disabled. [mkp: typo] Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth.c | 8 +++--- drivers/scsi/gdth_proc.c | 71 ++++++++++++++---------------------------------- drivers/scsi/gdth_proc.h | 3 -- 3 files changed, 25 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index dd6784e03a57..87786e8fdf14 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -4239,7 +4239,7 @@ static int ioc_general(void __user *arg, char *cmnd) gdth_ioctl_general gen; gdth_ha_str *ha; char *buf = NULL; - u64 paddr; + dma_addr_t paddr; int rval; if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general))) @@ -4256,8 +4256,8 @@ static int ioc_general(void __user *arg, char *cmnd) return -EINVAL; if (gen.data_len + gen.sense_len > 0) { - buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len, FALSE, - &paddr); + buf = pci_alloc_consistent(ha->pdev, + gen.data_len + gen.sense_len, &paddr); if (!buf) return -EFAULT; @@ -4292,7 +4292,7 @@ static int ioc_general(void __user *arg, char *cmnd) rval = 0; out_free_buf: - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); + pci_free_consistent(ha->pdev, gen.data_len + gen.sense_len, buf, paddr); return rval; } diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index bd5532a80b0e..8e77f8fd8641 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -31,7 +31,6 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, int i, found; gdth_cmd_str gdtcmd; gdth_cpar_str *pcpar; - u64 paddr; char cmnd[MAX_COMMAND_SIZE]; memset(cmnd, 0xff, 12); @@ -113,13 +112,23 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, } if (wb_mode) { - if (!gdth_ioctl_alloc(ha, sizeof(gdth_cpar_str), TRUE, &paddr)) - return(-EBUSY); + unsigned long flags; + + BUILD_BUG_ON(sizeof(gdth_cpar_str) > GDTH_SCRATCH); + + spin_lock_irqsave(&ha->smp_lock, flags); + if (ha->scratch_busy) { + spin_unlock_irqrestore(&ha->smp_lock, flags); + return -EBUSY; + } + ha->scratch_busy = TRUE; + spin_unlock_irqrestore(&ha->smp_lock, flags); + pcpar = (gdth_cpar_str *)ha->pscratch; memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) ); gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = paddr; + gdtcmd.u.ioctl.p_param = ha->scratch_phys; gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str); gdtcmd.u.ioctl.subfunc = CACHE_CONFIG; gdtcmd.u.ioctl.channel = INVALID_CHANNEL; @@ -127,7 +136,10 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, gdth_execute(host, &gdtcmd, cmnd, 30, NULL); - gdth_ioctl_free(ha, GDTH_SCRATCH, ha->pscratch, paddr); + spin_lock_irqsave(&ha->smp_lock, flags); + ha->scratch_busy = FALSE; + spin_unlock_irqrestore(&ha->smp_lock, flags); + printk("Done.\n"); return(orig_length); } @@ -143,7 +155,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) int id, i, j, k, sec, flag; int no_mdrv = 0, drv_no, is_mirr; u32 cnt; - u64 paddr; + dma_addr_t paddr; int rc = -ENOMEM; gdth_cmd_str *gdtcmd; @@ -232,7 +244,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) seq_puts(m, "\nPhysical Devices:"); flag = FALSE; - buf = gdth_ioctl_alloc(ha, size, FALSE, &paddr); + buf = pci_alloc_consistent(ha->pdev, size, &paddr); if (!buf) goto stop_output; for (i = 0; i < ha->bus_cnt; ++i) { @@ -406,7 +418,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) seq_printf(m, " To Array Drv.:\t%s\n", hrec); } - + if (!flag) seq_puts(m, "\n --\n"); @@ -500,7 +512,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) } } } - gdth_ioctl_free(ha, size, buf, paddr); + pci_free_consistent(ha->pdev, size, buf, paddr); for (i = 0; i < MAX_HDRIVES; ++i) { if (!(ha->hdr[i].present)) @@ -553,47 +565,6 @@ free_fail: return rc; } -static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, - u64 *paddr) -{ - unsigned long flags; - char *ret_val; - - if (size == 0) - return NULL; - - spin_lock_irqsave(&ha->smp_lock, flags); - - if (!ha->scratch_busy && size <= GDTH_SCRATCH) { - ha->scratch_busy = TRUE; - ret_val = ha->pscratch; - *paddr = ha->scratch_phys; - } else if (scratch) { - ret_val = NULL; - } else { - dma_addr_t dma_addr; - - ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr); - *paddr = dma_addr; - } - - spin_unlock_irqrestore(&ha->smp_lock, flags); - return ret_val; -} - -static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr) -{ - unsigned long flags; - - if (buf == ha->pscratch) { - spin_lock_irqsave(&ha->smp_lock, flags); - ha->scratch_busy = FALSE; - spin_unlock_irqrestore(&ha->smp_lock, flags); - } else { - pci_free_consistent(ha->pdev, size, buf, paddr); - } -} - #ifdef GDTH_IOCTL_PROC static int gdth_ioctl_check_bin(gdth_ha_str *ha, u16 size) { diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h index d7d0aa283695..4cc5377cb92e 100644 --- a/drivers/scsi/gdth_proc.h +++ b/drivers/scsi/gdth_proc.h @@ -12,9 +12,6 @@ int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd, static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, int length, gdth_ha_str *ha); -static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, - u64 *paddr); -static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr); static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id); #endif -- cgit v1.2.3 From 314814552a0adfa6f27f05165c609044e2baad9c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:21 +0100 Subject: scsi: gdth: remove ISA and EISA support The non-PCI code has bitrotted for quite a while and will just oops on load because it passes a NULL pointer to the PCI DMA routines. Lets kill it for good - if someone really wants to use one of these cards I'll help mentoring them to write a proper driver glue. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 2 +- drivers/scsi/gdth.c | 709 ++------------------------------------------------- drivers/scsi/gdth.h | 30 --- 3 files changed, 24 insertions(+), 717 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index f38882f6f37d..4d5d79d56f4b 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -665,7 +665,7 @@ config SCSI_DMX3191D config SCSI_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" - depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API + depends on PCI && SCSI ---help--- Formerly called GDT SCSI Disk Array Controller Support. diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 87786e8fdf14..da58ac703cbb 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -1,6 +1,6 @@ /************************************************************************ * Linux driver for * - * ICP vortex GmbH: GDT ISA/EISA/PCI Disk Array Controllers * + * ICP vortex GmbH: GDT PCI Disk Array Controllers * * Intel Corporation: Storage RAID Controllers * * * * gdth.c * @@ -32,15 +32,10 @@ ************************************************************************/ /* All GDT Disk Array Controllers are fully supported by this driver. - * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the + * This includes the PCI SCSI Disk Array Controllers and the * PCI Fibre Channel Disk Array Controllers. See gdth.h for a complete * list of all controller types. * - * If you have one or more GDT3000/3020 EISA controllers with - * controller BIOS disabled, you have to set the IRQ values with the - * command line option "gdth=irq1,irq2,...", where the irq1,irq2,... are - * the IRQ values for the EISA controllers. - * * After the optional list of IRQ values, other possible * command line options are: * disable:Y disable driver @@ -61,14 +56,12 @@ * access a shared resource from several nodes, * appropriate controller firmware required * shared_access:N enable driver reserve/release protocol - * probe_eisa_isa:Y scan for EISA/ISA controllers - * probe_eisa_isa:N do not scan for EISA/ISA controllers * force_dma32:Y use only 32 bit DMA mode * force_dma32:N use 64 bit DMA mode, if supported * * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N, * max_ids:127,rescan:N,hdr_channel:0, - * shared_access:Y,probe_eisa_isa:N,force_dma32:N". + * shared_access:Y,force_dma32:N". * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y". * * When loading the gdth driver as a module, the same options are available. @@ -79,7 +72,7 @@ * * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0 * max_ids=127 rescan=0 hdr_channel=0 shared_access=0 - * probe_eisa_isa=0 force_dma32=0" + * force_dma32=0" * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1". */ @@ -286,12 +279,6 @@ static struct timer_list gdth_timer; #define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b)) -#ifdef CONFIG_ISA -static u8 gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ -#endif -#if defined(CONFIG_EISA) || defined(CONFIG_ISA) -static u8 gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ -#endif static u8 gdth_polling; /* polling if TRUE */ static int gdth_ctr_count = 0; /* controller count */ static LIST_HEAD(gdth_instances); /* controller list */ @@ -325,10 +312,6 @@ static u8 gdth_direction_tab[0x100] = { }; /* LILO and modprobe/insmod parameters */ -/* IRQ list for GDT3000/3020 EISA controllers */ -static int irq[MAXHA] __initdata = -{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; /* disable driver flag */ static int disable __initdata = 0; /* reserve flag */ @@ -348,13 +331,10 @@ static int max_ids = MAXID; static int rescan = 0; /* shared access */ static int shared_access = 1; -/* enable support for EISA and ISA controllers */ -static int probe_eisa_isa = 0; /* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */ static int force_dma32 = 0; /* parameters for modprobe/insmod */ -module_param_hw_array(irq, int, irq, NULL, 0); module_param(disable, int, 0); module_param(reserve_mode, int, 0); module_param_array(reserve_list, int, NULL, 0); @@ -363,7 +343,6 @@ module_param(hdr_channel, int, 0); module_param(max_ids, int, 0); module_param(rescan, int, 0); module_param(shared_access, int, 0); -module_param(probe_eisa_isa, int, 0); module_param(force_dma32, int, 0); MODULE_AUTHOR("Achim Leubner"); MODULE_LICENSE("GPL"); @@ -515,45 +494,6 @@ static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs) } } -/* controller search and initialization functions */ -#ifdef CONFIG_EISA -static int __init gdth_search_eisa(u16 eisa_adr) -{ - u32 id; - - TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr)); - id = inl(eisa_adr+ID0REG); - if (id == GDT3A_ID || id == GDT3B_ID) { /* GDT3000A or GDT3000B */ - if ((inb(eisa_adr+EISAREG) & 8) == 0) - return 0; /* not EISA configured */ - return 1; - } - if (id == GDT3_ID) /* GDT3000 */ - return 1; - - return 0; -} -#endif /* CONFIG_EISA */ - -#ifdef CONFIG_ISA -static int __init gdth_search_isa(u32 bios_adr) -{ - void __iomem *addr; - u32 id; - - TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr)); - if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(u32))) != NULL) { - id = readl(addr); - iounmap(addr); - if (id == GDT2_ID) /* GDT2000 */ - return 1; - } - return 0; -} -#endif /* CONFIG_ISA */ - -#ifdef CONFIG_PCI - static bool gdth_search_vortex(u16 device) { if (device <= PCI_DEVICE_ID_VORTEX_GDT6555) @@ -656,204 +596,7 @@ static int gdth_pci_init_one(struct pci_dev *pdev, return 0; } -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_EISA -static int __init gdth_init_eisa(u16 eisa_adr,gdth_ha_str *ha) -{ - u32 retries,id; - u8 prot_ver,eisacf,i,irq_found; - - TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr)); - - /* disable board interrupts, deinitialize services */ - outb(0xff,eisa_adr+EDOORREG); - outb(0x00,eisa_adr+EDENABREG); - outb(0x00,eisa_adr+EINTENABREG); - - outb(0xff,eisa_adr+LDOORREG); - retries = INIT_RETRIES; - gdth_delay(20); - while (inb(eisa_adr+EDOORREG) != 0xff) { - if (--retries == 0) { - printk("GDT-EISA: Initialization error (DEINIT failed)\n"); - return 0; - } - gdth_delay(1); - TRACE2(("wait for DEINIT: retries=%d\n",retries)); - } - prot_ver = inb(eisa_adr+MAILBOXREG); - outb(0xff,eisa_adr+EDOORREG); - if (prot_ver != PROTOCOL_VERSION) { - printk("GDT-EISA: Illegal protocol version\n"); - return 0; - } - ha->bmic = eisa_adr; - ha->brd_phys = (u32)eisa_adr >> 12; - - outl(0,eisa_adr+MAILBOXREG); - outl(0,eisa_adr+MAILBOXREG+4); - outl(0,eisa_adr+MAILBOXREG+8); - outl(0,eisa_adr+MAILBOXREG+12); - - /* detect IRQ */ - if ((id = inl(eisa_adr+ID0REG)) == GDT3_ID) { - ha->oem_id = OEM_ID_ICP; - ha->type = GDT_EISA; - ha->stype = id; - outl(1,eisa_adr+MAILBOXREG+8); - outb(0xfe,eisa_adr+LDOORREG); - retries = INIT_RETRIES; - gdth_delay(20); - while (inb(eisa_adr+EDOORREG) != 0xfe) { - if (--retries == 0) { - printk("GDT-EISA: Initialization error (get IRQ failed)\n"); - return 0; - } - gdth_delay(1); - } - ha->irq = inb(eisa_adr+MAILBOXREG); - outb(0xff,eisa_adr+EDOORREG); - TRACE2(("GDT3000/3020: IRQ=%d\n",ha->irq)); - /* check the result */ - if (ha->irq == 0) { - TRACE2(("Unknown IRQ, use IRQ table from cmd line !\n")); - for (i = 0, irq_found = FALSE; - i < MAXHA && irq[i] != 0xff; ++i) { - if (irq[i]==10 || irq[i]==11 || irq[i]==12 || irq[i]==14) { - irq_found = TRUE; - break; - } - } - if (irq_found) { - ha->irq = irq[i]; - irq[i] = 0; - printk("GDT-EISA: Can not detect controller IRQ,\n"); - printk("Use IRQ setting from command line (IRQ = %d)\n", - ha->irq); - } else { - printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n"); - printk("the controller BIOS or use command line parameters\n"); - return 0; - } - } - } else { - eisacf = inb(eisa_adr+EISAREG) & 7; - if (eisacf > 4) /* level triggered */ - eisacf -= 4; - ha->irq = gdth_irq_tab[eisacf]; - ha->oem_id = OEM_ID_ICP; - ha->type = GDT_EISA; - ha->stype = id; - } - - ha->dma64_support = 0; - return 1; -} -#endif /* CONFIG_EISA */ - -#ifdef CONFIG_ISA -static int __init gdth_init_isa(u32 bios_adr,gdth_ha_str *ha) -{ - register gdt2_dpram_str __iomem *dp2_ptr; - int i; - u8 irq_drq,prot_ver; - u32 retries; - - TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr)); - - ha->brd = ioremap(bios_adr, sizeof(gdt2_dpram_str)); - if (ha->brd == NULL) { - printk("GDT-ISA: Initialization error (DPMEM remap error)\n"); - return 0; - } - dp2_ptr = ha->brd; - writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */ - /* reset interface area */ - memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u)); - if (readl(&dp2_ptr->u) != 0) { - printk("GDT-ISA: Initialization error (DPMEM write error)\n"); - iounmap(ha->brd); - return 0; - } - - /* disable board interrupts, read DRQ and IRQ */ - writeb(0xff, &dp2_ptr->io.irqdel); - writeb(0x00, &dp2_ptr->io.irqen); - writeb(0x00, &dp2_ptr->u.ic.S_Status); - writeb(0x00, &dp2_ptr->u.ic.Cmd_Index); - - irq_drq = readb(&dp2_ptr->io.rq); - for (i=0; i<3; ++i) { - if ((irq_drq & 1)==0) - break; - irq_drq >>= 1; - } - ha->drq = gdth_drq_tab[i]; - - irq_drq = readb(&dp2_ptr->io.rq) >> 3; - for (i=1; i<5; ++i) { - if ((irq_drq & 1)==0) - break; - irq_drq >>= 1; - } - ha->irq = gdth_irq_tab[i]; - - /* deinitialize services */ - writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]); - writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx); - writeb(0, &dp2_ptr->io.event); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) { - if (--retries == 0) { - printk("GDT-ISA: Initialization error (DEINIT failed)\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - prot_ver = (u8)readl(&dp2_ptr->u.ic.S_Info[0]); - writeb(0, &dp2_ptr->u.ic.Status); - writeb(0xff, &dp2_ptr->io.irqdel); - if (prot_ver != PROTOCOL_VERSION) { - printk("GDT-ISA: Illegal protocol version\n"); - iounmap(ha->brd); - return 0; - } - - ha->oem_id = OEM_ID_ICP; - ha->type = GDT_ISA; - ha->ic_all_size = sizeof(dp2_ptr->u); - ha->stype= GDT2_ID; - ha->brd_phys = bios_adr >> 4; - - /* special request to controller BIOS */ - writel(0x00, &dp2_ptr->u.ic.S_Info[0]); - writel(0x00, &dp2_ptr->u.ic.S_Info[1]); - writel(0x01, &dp2_ptr->u.ic.S_Info[2]); - writel(0x00, &dp2_ptr->u.ic.S_Info[3]); - writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx); - writeb(0, &dp2_ptr->io.event); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) { - if (--retries == 0) { - printk("GDT-ISA: Initialization error\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - writeb(0, &dp2_ptr->u.ic.Status); - writeb(0xff, &dp2_ptr->io.irqdel); - - ha->dma64_support = 0; - return 1; -} -#endif /* CONFIG_ISA */ -#ifdef CONFIG_PCI static int gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, gdth_ha_str *ha) { @@ -1228,30 +971,19 @@ static int gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, return 1; } -#endif /* CONFIG_PCI */ /* controller protocol functions */ static void gdth_enable_int(gdth_ha_str *ha) { unsigned long flags; - gdt2_dpram_str __iomem *dp2_ptr; gdt6_dpram_str __iomem *dp6_ptr; gdt6m_dpram_str __iomem *dp6m_ptr; TRACE(("gdth_enable_int() hanum %d\n",ha->hanum)); spin_lock_irqsave(&ha->smp_lock, flags); - if (ha->type == GDT_EISA) { - outb(0xff, ha->bmic + EDOORREG); - outb(0xff, ha->bmic + EDENABREG); - outb(0x01, ha->bmic + EINTENABREG); - } else if (ha->type == GDT_ISA) { - dp2_ptr = ha->brd; - writeb(1, &dp2_ptr->io.irqdel); - writeb(0, &dp2_ptr->u.ic.Cmd_Index); - writeb(1, &dp2_ptr->io.irqen); - } else if (ha->type == GDT_PCI) { + if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; writeb(1, &dp6_ptr->io.irqdel); writeb(0, &dp6_ptr->u.ic.Cmd_Index); @@ -1275,12 +1007,7 @@ static u8 gdth_get_status(gdth_ha_str *ha) TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count)); - if (ha->type == GDT_EISA) - IStatus = inb((u16)ha->bmic + EDOORREG); - else if (ha->type == GDT_ISA) - IStatus = - readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); - else if (ha->type == GDT_PCI) + if (ha->type == GDT_PCI) IStatus = readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); else if (ha->type == GDT_PCINEW) @@ -1298,11 +1025,7 @@ static int gdth_test_busy(gdth_ha_str *ha) TRACE(("gdth_test_busy() hanum %d\n", ha->hanum)); - if (ha->type == GDT_EISA) - gdtsema0 = (int)inb(ha->bmic + SEMA0REG); - else if (ha->type == GDT_ISA) - gdtsema0 = (int)readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); - else if (ha->type == GDT_PCI) + if (ha->type == GDT_PCI) gdtsema0 = (int)readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); else if (ha->type == GDT_PCINEW) gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg)); @@ -1336,11 +1059,7 @@ static void gdth_set_sema0(gdth_ha_str *ha) { TRACE(("gdth_set_sema0() hanum %d\n", ha->hanum)); - if (ha->type == GDT_EISA) { - outb(1, ha->bmic + SEMA0REG); - } else if (ha->type == GDT_ISA) { - writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); - } else if (ha->type == GDT_PCI) { + if (ha->type == GDT_PCI) { writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); } else if (ha->type == GDT_PCINEW) { outb(1, PTR2USHORT(&ha->plx->sema0_reg)); @@ -1356,7 +1075,6 @@ static void gdth_copy_command(gdth_ha_str *ha) register gdt6m_dpram_str __iomem *dp6m_ptr; register gdt6c_dpram_str __iomem *dp6c_ptr; gdt6_dpram_str __iomem *dp6_ptr; - gdt2_dpram_str __iomem *dp2_ptr; u16 cp_count,dp_offset,cmd_no; TRACE(("gdth_copy_command() hanum %d\n", ha->hanum)); @@ -1367,8 +1085,6 @@ static void gdth_copy_command(gdth_ha_str *ha) cmd_ptr = ha->pccb; ++ha->cmd_cnt; - if (ha->type == GDT_EISA) - return; /* no DPMEM, no copy */ /* set cpcount dword aligned */ if (cp_count & 3) @@ -1377,14 +1093,7 @@ static void gdth_copy_command(gdth_ha_str *ha) ha->cmd_offs_dpmem += cp_count; /* set offset and service, copy command to DPMEM */ - if (ha->type == GDT_ISA) { - dp2_ptr = ha->brd; - writew(dp_offset + DPMEM_COMMAND_OFFSET, - &dp2_ptr->u.ic.comm_queue[cmd_no].offset); - writew((u16)cmd_ptr->Service, - &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id); - memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); - } else if (ha->type == GDT_PCI) { + if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6_ptr->u.ic.comm_queue[cmd_no].offset); @@ -1430,13 +1139,7 @@ static void gdth_release_event(gdth_ha_str *ha) if (ha->pccb->OpCode == GDT_INIT) ha->pccb->Service |= 0x80; - if (ha->type == GDT_EISA) { - if (ha->pccb->OpCode == GDT_INIT) /* store DMA buffer */ - outl(ha->ccb_phys, ha->bmic + MAILBOXREG); - outb(ha->pccb->Service, ha->bmic + LDOORREG); - } else if (ha->type == GDT_ISA) { - writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event); - } else if (ha->type == GDT_PCI) { + if (ha->type == GDT_PCI) { writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event); } else if (ha->type == GDT_PCINEW) { outb(1, PTR2USHORT(&ha->plx->ldoor_reg)); @@ -2433,9 +2136,6 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n", scp->cmnd[0],scp->cmd_len,hdrive)); - if (ha->type==GDT_EISA && ha->cmd_cnt>0) - return 0; - mode64 = (ha->cache_feat & GDT_64BIT) ? TRUE : FALSE; /* test for READ_16, WRITE_16 if !mode64 ? --- not required, should not occur due to error return on @@ -2613,9 +2313,6 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 b) TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n", scp->cmnd[0],b,t,l)); - if (ha->type==GDT_EISA && ha->cmd_cnt>0) - return 0; - mode64 = (ha->raw_feat & GDT_64BIT) ? TRUE : FALSE; cmdp->Service = SCSIRAWSERVICE; @@ -2778,9 +2475,6 @@ static int gdth_special_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp) cmdp= ha->pccb; TRACE2(("gdth_special_cmd(): ")); - if (ha->type==GDT_EISA && ha->cmd_cnt>0) - return 0; - *cmdp = *cmndinfo->internal_cmd_str; cmdp->RequestBuffer = scp; @@ -2959,7 +2653,6 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, { gdt6m_dpram_str __iomem *dp6m_ptr = NULL; gdt6_dpram_str __iomem *dp6_ptr; - gdt2_dpram_str __iomem *dp2_ptr; struct scsi_cmnd *scp; int rval, i; u8 IStatus; @@ -3015,35 +2708,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, } #endif - if (ha->type == GDT_EISA) { - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = inw(ha->bmic + MAILBOXREG+8); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = inl(ha->bmic + MAILBOXREG+12); - ha->service = inw(ha->bmic + MAILBOXREG+10); - ha->info2 = inl(ha->bmic + MAILBOXREG+4); - - outb(0xff, ha->bmic + EDOORREG); /* acknowledge interrupt */ - outb(0x00, ha->bmic + SEMA1REG); /* reset status semaphore */ - } else if (ha->type == GDT_ISA) { - dp2_ptr = ha->brd; - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = readw(&dp2_ptr->u.ic.Status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = readl(&dp2_ptr->u.ic.Info[0]); - ha->service = readw(&dp2_ptr->u.ic.Service); - ha->info2 = readl(&dp2_ptr->u.ic.Info[1]); - - writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */ - writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */ - writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ - } else if (ha->type == GDT_PCI) { + if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; @@ -3610,12 +3275,7 @@ static int gdth_async_event(gdth_ha_str *ha) + sizeof(u64); ha->cmd_cnt = 0; gdth_copy_command(ha); - if (ha->type == GDT_EISA) - printk("[EISA slot %d] ",(u16)ha->brd_phys); - else if (ha->type == GDT_ISA) - printk("[DPMEM 0x%4X] ",(u16)ha->brd_phys); - else - printk("[PCI %d/%d] ",(u16)(ha->brd_phys>>8), + printk("[PCI %d/%d] ",(u16)(ha->brd_phys>>8), (u16)((ha->brd_phys>>3)&0x1f)); gdth_release_event(ha); } @@ -3756,23 +3416,12 @@ static inline void gdth_timer_init(void) static void __init internal_setup(char *str,int *ints) { - int i, argc; + int i; char *cur_str, *argv; TRACE2(("internal_setup() str %s ints[0] %d\n", str ? str:"NULL", ints ? ints[0]:0)); - /* read irq[] from ints[] */ - if (ints) { - argc = ints[0]; - if (argc > 0) { - if (argc > MAXHA) - argc = MAXHA; - for (i = 0; i < argc; ++i) - irq[i] = ints[i+1]; - } - } - /* analyse string */ argv = str; while (argv && (cur_str = strchr(argv, ':'))) { @@ -3799,8 +3448,6 @@ static void __init internal_setup(char *str,int *ints) rescan = val; else if (!strncmp(argv, "shared_access:", 14)) shared_access = val; - else if (!strncmp(argv, "probe_eisa_isa:", 15)) - probe_eisa_isa = val; else if (!strncmp(argv, "reserve_list:", 13)) { reserve_list[0] = val; for (i = 1; i < MAX_RES_ARGS; i++) { @@ -3847,18 +3494,7 @@ static const char *gdth_ctr_name(gdth_ha_str *ha) { TRACE2(("gdth_ctr_name()\n")); - if (ha->type == GDT_EISA) { - switch (ha->stype) { - case GDT3_ID: - return("GDT3000/3020"); - case GDT3A_ID: - return("GDT3000A/3020A/3050A"); - case GDT3B_ID: - return("GDT3000B/3010A"); - } - } else if (ha->type == GDT_ISA) { - return("GDT2000/2020"); - } else if (ha->type == GDT_PCI) { + if (ha->type == GDT_PCI) { switch (ha->pdev->device) { case PCI_DEVICE_ID_VORTEX_GDT60x0: return("GDT6000/6020/6050"); @@ -4528,22 +4164,17 @@ static int gdth_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) (NULL == (ha = gdth_find_ha(ctrt.ionode)))) return -EFAULT; - if (ha->type == GDT_ISA || ha->type == GDT_EISA) { - ctrt.type = (u8)((ha->stype>>20) - 0x10); + if (ha->type != GDT_PCIMPR) { + ctrt.type = (u8)((ha->stype<<4) + 6); } else { - if (ha->type != GDT_PCIMPR) { - ctrt.type = (u8)((ha->stype<<4) + 6); - } else { - ctrt.type = - (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); - if (ha->stype >= 0x300) - ctrt.ext_type = 0x6000 | ha->pdev->subsystem_device; - else - ctrt.ext_type = 0x6000 | ha->stype; - } - ctrt.device_id = ha->pdev->device; - ctrt.sub_device_id = ha->pdev->subsystem_device; + ctrt.type = (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); + if (ha->stype >= 0x300) + ctrt.ext_type = 0x6000 | ha->pdev->subsystem_device; + else + ctrt.ext_type = 0x6000 | ha->stype; } + ctrt.device_id = ha->pdev->device; + ctrt.sub_device_id = ha->pdev->subsystem_device; ctrt.info = ha->brd_phys; ctrt.oem_id = ha->oem_id; if (copy_to_user(argp, &ctrt, sizeof(gdth_ioctl_ctrtype))) @@ -4697,272 +4328,6 @@ static struct scsi_host_template gdth_template = { .no_write_same = 1, }; -#ifdef CONFIG_ISA -static int __init gdth_isa_probe_one(u32 isa_bios) -{ - struct Scsi_Host *shp; - gdth_ha_str *ha; - dma_addr_t scratch_dma_handle = 0; - int error, i; - - if (!gdth_search_isa(isa_bios)) - return -ENXIO; - - shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); - if (!shp) - return -ENOMEM; - ha = shost_priv(shp); - - error = -ENODEV; - if (!gdth_init_isa(isa_bios,ha)) - goto out_host_put; - - /* controller found and initialized */ - printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n", - isa_bios, ha->irq, ha->drq); - - error = request_irq(ha->irq, gdth_interrupt, 0, "gdth", ha); - if (error) { - printk("GDT-ISA: Unable to allocate IRQ\n"); - goto out_host_put; - } - - error = request_dma(ha->drq, "gdth"); - if (error) { - printk("GDT-ISA: Unable to allocate DMA channel\n"); - goto out_free_irq; - } - - set_dma_mode(ha->drq,DMA_MODE_CASCADE); - enable_dma(ha->drq); - shp->unchecked_isa_dma = 1; - shp->irq = ha->irq; - shp->dma_channel = ha->drq; - - ha->hanum = gdth_ctr_count++; - ha->shost = shp; - - ha->pccb = &ha->cmdext; - ha->ccb_phys = 0L; - ha->pdev = NULL; - - error = -ENOMEM; - - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); - if (!ha->pscratch) - goto out_dec_counters; - ha->scratch_phys = scratch_dma_handle; - - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); - if (!ha->pmsg) - goto out_free_pscratch; - ha->msg_phys = scratch_dma_handle; - -#ifdef INT_COAL - ha->coal_stat = pci_alloc_consistent(ha->pdev, - sizeof(gdth_coal_status) * MAXOFFSETS, - &scratch_dma_handle); - if (!ha->coal_stat) - goto out_free_pmsg; - ha->coal_stat_phys = scratch_dma_handle; -#endif - - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i = 0; i < GDTH_MAXCMDS; ++i) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - error = -ENODEV; - if (!gdth_search_drives(ha)) { - printk("GDT-ISA: Error during device scan\n"); - goto out_free_coal_stat; - } - - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; - - if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) - shp->max_cmd_len = 16; - - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = ha->bus_cnt; - - spin_lock_init(&ha->smp_lock); - gdth_enable_int(ha); - - error = scsi_add_host(shp, NULL); - if (error) - goto out_free_coal_stat; - list_add_tail(&ha->list, &gdth_instances); - gdth_timer_init(); - - scsi_scan_host(shp); - - return 0; - - out_free_coal_stat: -#ifdef INT_COAL - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, - ha->coal_stat, ha->coal_stat_phys); - out_free_pmsg: -#endif - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - out_free_pscratch: - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - out_dec_counters: - gdth_ctr_count--; - out_free_irq: - free_irq(ha->irq, ha); - out_host_put: - scsi_host_put(shp); - return error; -} -#endif /* CONFIG_ISA */ - -#ifdef CONFIG_EISA -static int __init gdth_eisa_probe_one(u16 eisa_slot) -{ - struct Scsi_Host *shp; - gdth_ha_str *ha; - dma_addr_t scratch_dma_handle = 0; - int error, i; - - if (!gdth_search_eisa(eisa_slot)) - return -ENXIO; - - shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); - if (!shp) - return -ENOMEM; - ha = shost_priv(shp); - - error = -ENODEV; - if (!gdth_init_eisa(eisa_slot,ha)) - goto out_host_put; - - /* controller found and initialized */ - printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n", - eisa_slot >> 12, ha->irq); - - error = request_irq(ha->irq, gdth_interrupt, 0, "gdth", ha); - if (error) { - printk("GDT-EISA: Unable to allocate IRQ\n"); - goto out_host_put; - } - - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - - ha->hanum = gdth_ctr_count++; - ha->shost = shp; - - TRACE2(("EISA detect Bus 0: hanum %d\n", ha->hanum)); - - ha->pccb = &ha->cmdext; - ha->ccb_phys = 0L; - - error = -ENOMEM; - - ha->pdev = NULL; - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); - if (!ha->pscratch) - goto out_free_irq; - ha->scratch_phys = scratch_dma_handle; - - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); - if (!ha->pmsg) - goto out_free_pscratch; - ha->msg_phys = scratch_dma_handle; - -#ifdef INT_COAL - ha->coal_stat = pci_alloc_consistent(ha->pdev, - sizeof(gdth_coal_status) * MAXOFFSETS, - &scratch_dma_handle); - if (!ha->coal_stat) - goto out_free_pmsg; - ha->coal_stat_phys = scratch_dma_handle; -#endif - - ha->ccb_phys = pci_map_single(ha->pdev,ha->pccb, - sizeof(gdth_cmd_str), PCI_DMA_BIDIRECTIONAL); - if (!ha->ccb_phys) - goto out_free_coal_stat; - - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i = 0; i < GDTH_MAXCMDS; ++i) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - if (!gdth_search_drives(ha)) { - printk("GDT-EISA: Error during device scan\n"); - error = -ENODEV; - goto out_free_ccb_phys; - } - - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; - - if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) - shp->max_cmd_len = 16; - - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = ha->bus_cnt; - - spin_lock_init(&ha->smp_lock); - gdth_enable_int(ha); - - error = scsi_add_host(shp, NULL); - if (error) - goto out_free_ccb_phys; - list_add_tail(&ha->list, &gdth_instances); - gdth_timer_init(); - - scsi_scan_host(shp); - - return 0; - - out_free_ccb_phys: - pci_unmap_single(ha->pdev,ha->ccb_phys, sizeof(gdth_cmd_str), - PCI_DMA_BIDIRECTIONAL); - out_free_coal_stat: -#ifdef INT_COAL - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, - ha->coal_stat, ha->coal_stat_phys); - out_free_pmsg: -#endif - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - out_free_pscratch: - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - out_free_irq: - free_irq(ha->irq, ha); - gdth_ctr_count--; - out_host_put: - scsi_host_put(shp); - return error; -} -#endif /* CONFIG_EISA */ - -#ifdef CONFIG_PCI static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) { struct Scsi_Host *shp; @@ -5105,7 +4470,6 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) scsi_host_put(shp); return error; } -#endif /* CONFIG_PCI */ static void gdth_remove_one(gdth_ha_str *ha) { @@ -5125,10 +4489,6 @@ static void gdth_remove_one(gdth_ha_str *ha) if (shp->irq) free_irq(shp->irq,ha); -#ifdef CONFIG_ISA - if (shp->dma_channel != 0xff) - free_dma(shp->dma_channel); -#endif #ifdef INT_COAL if (ha->coal_stat) pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * @@ -5181,26 +4541,6 @@ static int __init gdth_init(void) gdth_clear_events(); timer_setup(&gdth_timer, gdth_timeout, 0); - /* As default we do not probe for EISA or ISA controllers */ - if (probe_eisa_isa) { - /* scanning for controllers, at first: ISA controller */ -#ifdef CONFIG_ISA - u32 isa_bios; - for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL; - isa_bios += 0x8000UL) - gdth_isa_probe_one(isa_bios); -#endif -#ifdef CONFIG_EISA - { - u16 eisa_slot; - for (eisa_slot = 0x1000; eisa_slot <= 0x8000; - eisa_slot += 0x1000) - gdth_eisa_probe_one(eisa_slot); - } -#endif - } - -#ifdef CONFIG_PCI /* scanning for PCI controllers */ if (pci_register_driver(&gdth_pci_driver)) { gdth_ha_str *ha; @@ -5209,7 +4549,6 @@ static int __init gdth_init(void) gdth_remove_one(ha); return -ENODEV; } -#endif /* CONFIG_PCI */ TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count)); @@ -5230,9 +4569,7 @@ static void __exit gdth_exit(void) del_timer_sync(&gdth_timer); #endif -#ifdef CONFIG_PCI pci_unregister_driver(&gdth_pci_driver); -#endif list_for_each_entry(ha, &gdth_instances, list) gdth_remove_one(ha); diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index ee6ffcf388e8..5a13d406d40e 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -38,17 +38,9 @@ #define OEM_ID_INTEL 0x8000 /* controller classes */ -#define GDT_ISA 0x01 /* ISA controller */ -#define GDT_EISA 0x02 /* EISA controller */ #define GDT_PCI 0x03 /* PCI controller */ #define GDT_PCINEW 0x04 /* new PCI controller */ #define GDT_PCIMPR 0x05 /* PCI MPR controller */ -/* GDT_EISA, controller subtypes EISA */ -#define GDT3_ID 0x0130941c /* GDT3000/3020 */ -#define GDT3A_ID 0x0230941c /* GDT3000A/3020A/3050A */ -#define GDT3B_ID 0x0330941c /* GDT3000B/3010A */ -/* GDT_ISA */ -#define GDT2_ID 0x0120941c /* GDT2000/2020 */ #ifndef PCI_DEVICE_ID_VORTEX_GDT60x0 /* GDT_PCI */ @@ -281,17 +273,6 @@ #define GDTH_DATA_IN 0x01000000L /* data from target */ #define GDTH_DATA_OUT 0x00000000L /* data to target */ -/* BMIC registers (EISA controllers) */ -#define ID0REG 0x0c80 /* board ID */ -#define EINTENABREG 0x0c89 /* interrupt enable */ -#define SEMA0REG 0x0c8a /* command semaphore */ -#define SEMA1REG 0x0c8b /* status semaphore */ -#define LDOORREG 0x0c8d /* local doorbell */ -#define EDENABREG 0x0c8e /* EISA system doorbell enab. */ -#define EDOORREG 0x0c8f /* EISA system doorbell */ -#define MAILBOXREG 0x0c90 /* mailbox reg. (16 bytes) */ -#define EISAREG 0x0cc0 /* EISA configuration */ - /* other defines */ #define LINUX_OS 8 /* used for cache optim. */ #define SECS32 0x1f /* round capacity */ @@ -706,21 +687,11 @@ typedef struct { u8 fw_magic; /* contr. ID from firmware */ } __attribute__((packed)) gdt_pci_sram; -/* SRAM structure EISA controllers (but NOT GDT3000/3020) */ -typedef struct { - u8 os_used[16]; /* OS code per service */ - u16 need_deinit; /* switch betw. BIOS/driver */ - u8 switch_support; /* see need_deinit */ - u8 padding; -} __attribute__((packed)) gdt_eisa_sram; - - /* DPRAM ISA controllers */ typedef struct { union { struct { u8 bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */ - u32 magic; /* controller (EISA) ID */ u16 need_deinit; /* switch betw. BIOS/driver */ u8 switch_support; /* see need_deinit */ u8 padding[9]; @@ -843,7 +814,6 @@ typedef struct { u16 cache_feat; /* feat. cache serv. (s/g,..)*/ u16 raw_feat; /* feat. raw service (s/g,..)*/ u16 screen_feat; /* feat. raw service (s/g,..)*/ - u16 bmic; /* BMIC address (EISA) */ void __iomem *brd; /* DPRAM address */ u32 brd_phys; /* slot number/BIOS address */ gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */ -- cgit v1.2.3 From adfa080bf2f985cef33108c3df009f90fdafa450 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:22 +0100 Subject: scsi: gdth: remove direct serial port access Remove never compile in support for sending debug traces straight to the serial port using direct port access. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth.c | 70 ----------------------------------------------------- 1 file changed, 70 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index da58ac703cbb..9e81b9655c2d 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -185,79 +185,9 @@ static void gdth_scsi_done(struct scsi_cmnd *scp); #ifdef DEBUG_GDTH static u8 DebugState = DEBUG_GDTH; - -#ifdef __SERIAL__ -#define MAX_SERBUF 160 -static void ser_init(void); -static void ser_puts(char *str); -static void ser_putc(char c); -static int ser_printk(const char *fmt, ...); -static char strbuf[MAX_SERBUF+1]; -#ifdef __COM2__ -#define COM_BASE 0x2f8 -#else -#define COM_BASE 0x3f8 -#endif -static void ser_init() -{ - unsigned port=COM_BASE; - - outb(0x80,port+3); - outb(0,port+1); - /* 19200 Baud, if 9600: outb(12,port) */ - outb(6, port); - outb(3,port+3); - outb(0,port+1); - /* - ser_putc('I'); - ser_putc(' '); - */ -} - -static void ser_puts(char *str) -{ - char *ptr; - - ser_init(); - for (ptr=str;*ptr;++ptr) - ser_putc(*ptr); -} - -static void ser_putc(char c) -{ - unsigned port=COM_BASE; - - while ((inb(port+5) & 0x20)==0); - outb(c,port); - if (c==0x0a) - { - while ((inb(port+5) & 0x20)==0); - outb(0x0d,port); - } -} - -static int ser_printk(const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args,fmt); - i = vsprintf(strbuf,fmt,args); - ser_puts(strbuf); - va_end(args); - return i; -} - -#define TRACE(a) {if (DebugState==1) {ser_printk a;}} -#define TRACE2(a) {if (DebugState==1 || DebugState==2) {ser_printk a;}} -#define TRACE3(a) {if (DebugState!=0) {ser_printk a;}} - -#else /* !__SERIAL__ */ #define TRACE(a) {if (DebugState==1) {printk a;}} #define TRACE2(a) {if (DebugState==1 || DebugState==2) {printk a;}} #define TRACE3(a) {if (DebugState!=0) {printk a;}} -#endif - #else /* !DEBUG */ #define TRACE(a) #define TRACE2(a) -- cgit v1.2.3 From e09c142891a9362b91208f3423961e7d436b540f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:23 +0100 Subject: scsi: gdth: remove dead rtc code This code has been under the never defined GDTH_RTC ifdef forever, nuke it. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth.c | 32 -------------------------------- 1 file changed, 32 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 9e81b9655c2d..8e80902d909e 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -115,10 +115,6 @@ #include #include #include - -#ifdef GDTH_RTC -#include -#endif #include #include @@ -1197,11 +1193,6 @@ static int gdth_search_drives(gdth_ha_str *ha) gdth_perf_modes *pmod; #endif -#ifdef GDTH_RTC - u8 rtc[12]; - unsigned long flags; -#endif - TRACE(("gdth_search_drives() hanum %d\n", ha->hanum)); ok = 0; @@ -1221,29 +1212,6 @@ static int gdth_search_drives(gdth_ha_str *ha) } TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n")); -#ifdef GDTH_RTC - /* read realtime clock info, send to controller */ - /* 1. wait for the falling edge of update flag */ - spin_lock_irqsave(&rtc_lock, flags); - for (j = 0; j < 1000000; ++j) - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (j = 0; j < 1000000; ++j) - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - /* 2. read info */ - do { - for (j = 0; j < 12; ++j) - rtc[j] = CMOS_READ(j); - } while (rtc[0] != CMOS_READ(0)); - spin_unlock_irqrestore(&rtc_lock, flags); - TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(u32 *)&rtc[0], - *(u32 *)&rtc[4], *(u32 *)&rtc[8])); - /* 3. send to controller firmware */ - gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(u32 *)&rtc[0], - *(u32 *)&rtc[4], *(u32 *)&rtc[8]); -#endif - /* unfreeze all IOs */ gdth_internal_cmd(ha, CACHESERVICE, GDT_UNFREEZE_IO, 0, 0, 0); -- cgit v1.2.3 From 1d978c336ae3067fd136b7238a60e928b922e9e7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:24 +0100 Subject: scsi: gdth: remove dead dma statistics code This code can't be built into the kernel without editing the source file and is not generally useful. [mkp: typo] Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth.c | 18 ------------------ drivers/scsi/gdth_proc.c | 8 -------- 2 files changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 8e80902d909e..93d9c2f14ab9 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -2126,12 +2126,6 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, cmdp->u.cache64.sg_canz = sgcnt; scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl); -#ifdef GDTH_DMA_STATISTICS - if (cmdp->u.cache64.sg_lst[i].sg_ptr > (u64)0xffffffff) - ha->dma64_cnt++; - else - ha->dma32_cnt++; -#endif cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl); } } else { @@ -2141,9 +2135,6 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, cmdp->u.cache.sg_canz = sgcnt; scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl); -#ifdef GDTH_DMA_STATISTICS - ha->dma32_cnt++; -#endif cmdp->u.cache.sg_lst[i].sg_len = sg_dma_len(sl); } } @@ -2298,12 +2289,6 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 b) cmdp->u.raw64.sg_ranz = sgcnt; scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl); -#ifdef GDTH_DMA_STATISTICS - if (cmdp->u.raw64.sg_lst[i].sg_ptr > (u64)0xffffffff) - ha->dma64_cnt++; - else - ha->dma32_cnt++; -#endif cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl); } } else { @@ -2313,9 +2298,6 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 b) cmdp->u.raw.sg_ranz = sgcnt; scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl); -#ifdef GDTH_DMA_STATISTICS - ha->dma32_cnt++; -#endif cmdp->u.raw.sg_lst[i].sg_len = sg_dma_len(sl); } } diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 8e77f8fd8641..fc36c49a5334 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -229,14 +229,6 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) " Serial No.: \t0x%8X\tCache RAM size:\t%d KB\n", ha->binfo.ser_no, ha->binfo.memsize / 1024); -#ifdef GDTH_DMA_STATISTICS - /* controller statistics */ - seq_puts(m, "\nController Statistics:\n"); - seq_printf(m, - " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n", - ha->dma32_cnt, ha->dma64_cnt); -#endif - if (ha->more_proc) { size_t size = max_t(size_t, GDTH_SCRATCH, sizeof(gdth_hget_str)); -- cgit v1.2.3 From 9affa597850fb53918f7069f73bb7235756a4dc7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:25 +0100 Subject: scsi: gdth: remove dead code under #ifdef GDTH_IOCTL_PROC This can't ever be compiled into the kernel, so remove it. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth_ioctl.h | 89 ----------------------------------------------- drivers/scsi/gdth_proc.c | 18 ---------- 2 files changed, 107 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth_ioctl.h b/drivers/scsi/gdth_ioctl.h index 4c91894ac244..ee4c9bf1022a 100644 --- a/drivers/scsi/gdth_ioctl.h +++ b/drivers/scsi/gdth_ioctl.h @@ -27,11 +27,7 @@ #define GDTH_MAXSG 32 /* max. s/g elements */ #define MAX_LDRIVES 255 /* max. log. drive count */ -#ifdef GDTH_IOCTL_PROC -#define MAX_HDRIVES 100 /* max. host drive count */ -#else #define MAX_HDRIVES MAX_LDRIVES /* max. host drive count */ -#endif /* scatter/gather element */ typedef struct { @@ -178,91 +174,6 @@ typedef struct { gdth_evt_data event_data; } __attribute__((packed)) gdth_evt_str; - -#ifdef GDTH_IOCTL_PROC -/* IOCTL structure (write) */ -typedef struct { - u32 magic; /* IOCTL magic */ - u16 ioctl; /* IOCTL */ - u16 ionode; /* controller number */ - u16 service; /* controller service */ - u16 timeout; /* timeout */ - union { - struct { - u8 command[512]; /* controller command */ - u8 data[1]; /* add. data */ - } general; - struct { - u8 lock; /* lock/unlock */ - u8 drive_cnt; /* drive count */ - u16 drives[MAX_HDRIVES];/* drives */ - } lockdrv; - struct { - u8 lock; /* lock/unlock */ - u8 channel; /* channel */ - } lockchn; - struct { - int erase; /* erase event ? */ - int handle; - u8 evt[EVENT_SIZE]; /* event structure */ - } event; - struct { - u8 bus; /* SCSI bus */ - u8 target; /* target ID */ - u8 lun; /* LUN */ - u8 cmd_len; /* command length */ - u8 cmd[12]; /* SCSI command */ - } scsi; - struct { - u16 hdr_no; /* host drive number */ - u8 flag; /* old meth./add/remove */ - } rescan; - } iu; -} gdth_iowr_str; - -/* IOCTL structure (read) */ -typedef struct { - u32 size; /* buffer size */ - u32 status; /* IOCTL error code */ - union { - struct { - u8 data[1]; /* data */ - } general; - struct { - u16 version; /* driver version */ - } drvers; - struct { - u8 type; /* controller type */ - u16 info; /* slot etc. */ - u16 oem_id; /* OEM ID */ - u16 bios_ver; /* not used */ - u16 access; /* not used */ - u16 ext_type; /* extended type */ - u16 device_id; /* device ID */ - u16 sub_device_id; /* sub device ID */ - } ctrtype; - struct { - u8 version; /* OS version */ - u8 subversion; /* OS subversion */ - u16 revision; /* revision */ - } osvers; - struct { - u16 count; /* controller count */ - } ctrcnt; - struct { - int handle; - u8 evt[EVENT_SIZE]; /* event structure */ - } event; - struct { - u8 bus; /* SCSI bus, 0xff: invalid */ - u8 target; /* target ID */ - u8 lun; /* LUN */ - u8 cluster_type; /* cluster properties */ - } hdr_list[MAX_HDRIVES]; /* index is host drive number */ - } iu; -} gdth_iord_str; -#endif - /* GDTIOCTL_GENERAL */ typedef struct { u16 ionode; /* controller number */ diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index fc36c49a5334..5a13ccac8dee 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -557,24 +557,6 @@ free_fail: return rc; } -#ifdef GDTH_IOCTL_PROC -static int gdth_ioctl_check_bin(gdth_ha_str *ha, u16 size) -{ - unsigned long flags; - int ret_val; - - spin_lock_irqsave(&ha->smp_lock, flags); - - ret_val = FALSE; - if (ha->scratch_busy) { - if (((gdth_iord_str *)ha->pscratch)->size == (u32)size) - ret_val = TRUE; - } - spin_unlock_irqrestore(&ha->smp_lock, flags); - return ret_val; -} -#endif - static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id) { unsigned long flags; -- cgit v1.2.3 From d8e1e6add226e57fe467483d117e4b6113fe2e2e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:26 +0100 Subject: scsi: gdth: remove interrupt coalescing support This code has been under a never defined ifdef since the beginning of time (or at least history), and has just bitrotted. Nuke it. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth.c | 151 +++++----------------------------------------------- 1 file changed, 12 insertions(+), 139 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 93d9c2f14ab9..878b9ccc3d6d 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -89,10 +89,6 @@ * phase: unused */ - -/* interrupt coalescing */ -/* #define INT_COAL */ - /* statistics */ #define GDTH_STATISTICS @@ -192,9 +188,6 @@ static u8 DebugState = DEBUG_GDTH; #ifdef GDTH_STATISTICS static u32 max_rq=0, max_index=0, max_sg=0; -#ifdef INT_COAL -static u32 max_int_coal=0; -#endif static u32 act_ints=0, act_ios=0, act_stats=0, act_rq=0; static struct timer_list gdth_timer; #endif @@ -1189,9 +1182,6 @@ static int gdth_search_drives(gdth_ha_str *ha) gdth_arcdl_str *alst; gdth_alist_str *alst2; gdth_oem_str_ioctl *oemstr; -#ifdef INT_COAL - gdth_perf_modes *pmod; -#endif TRACE(("gdth_search_drives() hanum %d\n", ha->hanum)); ok = 0; @@ -1234,35 +1224,6 @@ static int gdth_search_drives(gdth_ha_str *ha) cdev_cnt = (u16)ha->info; ha->fw_vers = ha->service; -#ifdef INT_COAL - if (ha->type == GDT_PCIMPR) { - /* set perf. modes */ - pmod = (gdth_perf_modes *)ha->pscratch; - pmod->version = 1; - pmod->st_mode = 1; /* enable one status buffer */ - *((u64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys; - pmod->st_buff_indx1 = COALINDEX; - pmod->st_buff_addr2 = 0; - pmod->st_buff_u_addr2 = 0; - pmod->st_buff_indx2 = 0; - pmod->st_buff_size = sizeof(gdth_coal_status) * MAXOFFSETS; - pmod->cmd_mode = 0; // disable all cmd buffers - pmod->cmd_buff_addr1 = 0; - pmod->cmd_buff_u_addr1 = 0; - pmod->cmd_buff_indx1 = 0; - pmod->cmd_buff_addr2 = 0; - pmod->cmd_buff_u_addr2 = 0; - pmod->cmd_buff_indx2 = 0; - pmod->cmd_buff_size = 0; - pmod->reserved1 = 0; - pmod->reserved2 = 0; - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SET_PERF_MODES, - INVALID_CHANNEL,sizeof(gdth_perf_modes))) { - printk("GDT-HA %d: Interrupt coalescing activated\n", ha->hanum); - } - } -#endif - /* detect number of buses - try new IOCTL */ iocr = (gdth_raw_iochan_str *)ha->pscratch; iocr->hdr.version = 0xffffffff; @@ -2538,12 +2499,6 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, u8 IStatus; u16 Service; unsigned long flags = 0; -#ifdef INT_COAL - int coalesced = FALSE; - int next = FALSE; - gdth_coal_status *pcs = NULL; - int act_int_coal = 0; -#endif TRACE(("gdth_interrupt() IRQ %d\n", ha->irq)); @@ -2570,24 +2525,6 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, ++act_ints; #endif -#ifdef INT_COAL - /* See if the fw is returning coalesced status */ - if (IStatus == COALINDEX) { - /* Coalesced status. Setup the initial status - buffer pointer and flags */ - pcs = ha->coal_stat; - coalesced = TRUE; - next = TRUE; - } - - do { - if (coalesced) { - /* For coalesced requests all status - information is found in the status buffer */ - IStatus = (u8)(pcs->status & 0xff); - } -#endif - if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ @@ -2620,28 +2557,15 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, dp6m_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; -#ifdef INT_COAL - if (coalesced) - ha->status = pcs->ext_status & 0xffff; - else -#endif - ha->status = readw(&dp6m_ptr->i960r.status); + ha->status = readw(&dp6m_ptr->i960r.status); TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else /* no error */ ha->status = S_OK; -#ifdef INT_COAL - /* get information */ - if (coalesced) { - ha->info = pcs->info0; - ha->info2 = pcs->info1; - ha->service = (pcs->ext_status >> 16) & 0xffff; - } else -#endif - { - ha->info = readl(&dp6m_ptr->i960r.info[0]); - ha->service = readw(&dp6m_ptr->i960r.service); - ha->info2 = readl(&dp6m_ptr->i960r.info[1]); - } + + ha->info = readl(&dp6m_ptr->i960r.info[0]); + ha->service = readw(&dp6m_ptr->i960r.service); + ha->info2 = readl(&dp6m_ptr->i960r.info[1]); + /* event string */ if (IStatus == ASYNCINDEX) { if (ha->service != SCREENSERVICE && @@ -2656,15 +2580,8 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, } } } -#ifdef INT_COAL - /* Make sure that non coalesced interrupts get cleared - before being handled by gdth_async_event/gdth_sync_event */ - if (!coalesced) -#endif - { - writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - writeb(0, &dp6m_ptr->i960r.sema1_reg); - } + writeb(0xff, &dp6m_ptr->i960r.edoor_reg); + writeb(0, &dp6m_ptr->i960r.sema1_reg); } else { TRACE2(("gdth_interrupt() unknown controller type\n")); if (!gdth_polling) @@ -2727,31 +2644,6 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, gdth_scsi_done(scp); } -#ifdef INT_COAL - if (coalesced) { - /* go to the next status in the status buffer */ - ++pcs; -#ifdef GDTH_STATISTICS - ++act_int_coal; - if (act_int_coal > max_int_coal) { - max_int_coal = act_int_coal; - printk("GDT: max_int_coal = %d\n",(u16)max_int_coal); - } -#endif - /* see if there is another status */ - if (pcs->status == 0) - /* Stop the coalesce loop */ - next = FALSE; - } - } while (next); - - /* coalescing only for new GDT_PCIMPR controllers available */ - if (ha->type == GDT_PCIMPR && coalesced) { - writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - writeb(0, &dp6m_ptr->i960r.sema1_reg); - } -#endif - gdth_next(ha); return IRQ_HANDLED; } @@ -4264,15 +4156,6 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) goto out_free_pscratch; ha->msg_phys = scratch_dma_handle; -#ifdef INT_COAL - ha->coal_stat = pci_alloc_consistent(ha->pdev, - sizeof(gdth_coal_status) * MAXOFFSETS, - &scratch_dma_handle); - if (!ha->coal_stat) - goto out_free_pmsg; - ha->coal_stat_phys = scratch_dma_handle; -#endif - ha->scratch_busy = FALSE; ha->req_first = NULL; ha->tid_cnt = pdev->device >= 0x200 ? MAXID : MAX_HDRIVES; @@ -4285,7 +4168,7 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) error = -ENODEV; if (!gdth_search_drives(ha)) { printk("GDT-PCI %d: Error during device scan\n", ha->hanum); - goto out_free_coal_stat; + goto out_free_pmsg; } if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) @@ -4298,7 +4181,7 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "GDT-PCI %d: " "Unable to set 32-bit DMA\n", ha->hanum); - goto out_free_coal_stat; + goto out_free_pmsg; } } else { shp->max_cmd_len = 16; @@ -4307,7 +4190,7 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "GDT-PCI %d: " "Unable to set 64/32-bit DMA\n", ha->hanum); - goto out_free_coal_stat; + goto out_free_pmsg; } } @@ -4320,7 +4203,7 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) error = scsi_add_host(shp, &pdev->dev); if (error) - goto out_free_coal_stat; + goto out_free_pmsg; list_add_tail(&ha->list, &gdth_instances); pci_set_drvdata(ha->pdev, ha); @@ -4332,12 +4215,7 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) return 0; - out_free_coal_stat: -#ifdef INT_COAL - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, - ha->coal_stat, ha->coal_stat_phys); out_free_pmsg: -#endif pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), ha->pmsg, ha->msg_phys); out_free_pscratch: @@ -4369,11 +4247,6 @@ static void gdth_remove_one(gdth_ha_str *ha) if (shp->irq) free_irq(shp->irq,ha); -#ifdef INT_COAL - if (ha->coal_stat) - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys); -#endif if (ha->pscratch) pci_free_consistent(ha->pdev, GDTH_SCRATCH, ha->pscratch, ha->scratch_phys); -- cgit v1.2.3 From bb327df8326eff8b12bfcca39b8e1f25f616b1c3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Dec 2018 08:41:27 +0100 Subject: scsi: gdth: use generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Also switch to dma_map_single from pci_map_page in one case where this makes the code simpler. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/gdth.c | 60 +++++++++++++++++++++++------------------------- drivers/scsi/gdth_proc.c | 4 ++-- 2 files changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 878b9ccc3d6d..e7f1dd4f3b66 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -2077,9 +2077,9 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, if (scsi_bufflen(scp)) { cmndinfo->dma_dir = (read_write == 1 ? - PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - sgcnt = pci_map_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), - cmndinfo->dma_dir); + DMA_TO_DEVICE : DMA_FROM_DEVICE); + sgcnt = dma_map_sg(&ha->pdev->dev, scsi_sglist(scp), + scsi_sg_count(scp), cmndinfo->dma_dir); if (mode64) { struct scatterlist *sl; @@ -2153,8 +2153,6 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 b) dma_addr_t sense_paddr; int cmd_index, sgcnt, mode64; u8 t,l; - struct page *page; - unsigned long offset; struct gdth_cmndinfo *cmndinfo; t = scp->device->id; @@ -2196,10 +2194,8 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 b) } } else { - page = virt_to_page(scp->sense_buffer); - offset = (unsigned long)scp->sense_buffer & ~PAGE_MASK; - sense_paddr = pci_map_page(ha->pdev,page,offset, - 16,PCI_DMA_FROMDEVICE); + sense_paddr = dma_map_single(&ha->pdev->dev, scp->sense_buffer, 16, + DMA_FROM_DEVICE); cmndinfo->sense_paddr = sense_paddr; cmdp->OpCode = GDT_WRITE; /* always */ @@ -2240,9 +2236,9 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 b) } if (scsi_bufflen(scp)) { - cmndinfo->dma_dir = PCI_DMA_BIDIRECTIONAL; - sgcnt = pci_map_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), - cmndinfo->dma_dir); + cmndinfo->dma_dir = DMA_BIDIRECTIONAL; + sgcnt = dma_map_sg(&ha->pdev->dev, scsi_sglist(scp), + scsi_sg_count(scp), cmndinfo->dma_dir); if (mode64) { struct scatterlist *sl; @@ -2750,12 +2746,12 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, return 2; } if (scsi_bufflen(scp)) - pci_unmap_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), + dma_unmap_sg(&ha->pdev->dev, scsi_sglist(scp), scsi_sg_count(scp), cmndinfo->dma_dir); if (cmndinfo->sense_paddr) - pci_unmap_page(ha->pdev, cmndinfo->sense_paddr, 16, - PCI_DMA_FROMDEVICE); + dma_unmap_page(&ha->pdev->dev, cmndinfo->sense_paddr, 16, + DMA_FROM_DEVICE); if (ha->status == S_OK) { cmndinfo->status = S_OK; @@ -3664,8 +3660,9 @@ static int ioc_general(void __user *arg, char *cmnd) return -EINVAL; if (gen.data_len + gen.sense_len > 0) { - buf = pci_alloc_consistent(ha->pdev, - gen.data_len + gen.sense_len, &paddr); + buf = dma_alloc_coherent(&ha->pdev->dev, + gen.data_len + gen.sense_len, &paddr, + GFP_KERNEL); if (!buf) return -EFAULT; @@ -3700,7 +3697,8 @@ static int ioc_general(void __user *arg, char *cmnd) rval = 0; out_free_buf: - pci_free_consistent(ha->pdev, gen.data_len + gen.sense_len, buf, paddr); + dma_free_coherent(&ha->pdev->dev, gen.data_len + gen.sense_len, buf, + paddr); return rval; } @@ -4144,14 +4142,14 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) error = -ENOMEM; - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); + ha->pscratch = dma_alloc_coherent(&ha->pdev->dev, GDTH_SCRATCH, + &scratch_dma_handle, GFP_KERNEL); if (!ha->pscratch) goto out_free_irq; ha->scratch_phys = scratch_dma_handle; - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); + ha->pmsg = dma_alloc_coherent(&ha->pdev->dev, sizeof(gdth_msg_str), + &scratch_dma_handle, GFP_KERNEL); if (!ha->pmsg) goto out_free_pscratch; ha->msg_phys = scratch_dma_handle; @@ -4178,16 +4176,16 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) /* 64-bit DMA only supported from FW >= x.43 */ if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) || !ha->dma64_support) { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "GDT-PCI %d: " "Unable to set 32-bit DMA\n", ha->hanum); goto out_free_pmsg; } } else { shp->max_cmd_len = 16; - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { printk("GDT-PCI %d: 64-bit DMA enabled\n", ha->hanum); - } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + } else if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "GDT-PCI %d: " "Unable to set 64/32-bit DMA\n", ha->hanum); goto out_free_pmsg; @@ -4216,10 +4214,10 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) return 0; out_free_pmsg: - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + dma_free_coherent(&ha->pdev->dev, sizeof(gdth_msg_str), ha->pmsg, ha->msg_phys); out_free_pscratch: - pci_free_consistent(ha->pdev, GDTH_SCRATCH, + dma_free_coherent(&ha->pdev->dev, GDTH_SCRATCH, ha->pscratch, ha->scratch_phys); out_free_irq: free_irq(ha->irq, ha); @@ -4248,14 +4246,14 @@ static void gdth_remove_one(gdth_ha_str *ha) free_irq(shp->irq,ha); if (ha->pscratch) - pci_free_consistent(ha->pdev, GDTH_SCRATCH, + dma_free_coherent(&ha->pdev->dev, GDTH_SCRATCH, ha->pscratch, ha->scratch_phys); if (ha->pmsg) - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + dma_free_coherent(&ha->pdev->dev, sizeof(gdth_msg_str), ha->pmsg, ha->msg_phys); if (ha->ccb_phys) - pci_unmap_single(ha->pdev,ha->ccb_phys, - sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); + dma_unmap_single(&ha->pdev->dev, ha->ccb_phys, + sizeof(gdth_cmd_str), DMA_BIDIRECTIONAL); scsi_host_put(shp); } diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 5a13ccac8dee..381d849726ac 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -236,7 +236,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) seq_puts(m, "\nPhysical Devices:"); flag = FALSE; - buf = pci_alloc_consistent(ha->pdev, size, &paddr); + buf = dma_alloc_coherent(&ha->pdev->dev, size, &paddr, GFP_KERNEL); if (!buf) goto stop_output; for (i = 0; i < ha->bus_cnt; ++i) { @@ -504,7 +504,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) } } } - pci_free_consistent(ha->pdev, size, buf, paddr); + dma_free_coherent(&ha->pdev->dev, size, buf, paddr); for (i = 0; i < MAX_HDRIVES; ++i) { if (!(ha->hdr[i].present)) -- cgit v1.2.3 From 381d66da721219d9c7d6b03b0e79fd30d23500e1 Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:24:03 +0800 Subject: scsi: arcmsr: Rename acb structure member roundup_ccbsize to ioqueue_size From Ching Huang Rename acb structure member roundup_ccbsize to ioqueue_size Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr.h | 2 +- drivers/scsi/arcmsr/arcmsr_hba.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 9c397a2794d6..256fe9a3ae1e 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -739,7 +739,7 @@ struct AdapterControlBlock #define ACB_ADAPTER_TYPE_C 0x00000002 /* hbc L IOP */ #define ACB_ADAPTER_TYPE_D 0x00000003 /* hbd M IOP */ #define ACB_ADAPTER_TYPE_E 0x00000004 /* hba L IOP */ - u32 roundup_ccbsize; + u32 ioqueue_size; struct pci_dev * pdev; struct Scsi_Host * host; unsigned long vir2phy_offset; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 0f6751b0a633..f3a7855deab5 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -229,7 +229,7 @@ static void arcmsr_free_mu(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: case ACB_ADAPTER_TYPE_D: case ACB_ADAPTER_TYPE_E: { - dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize, + dma_free_coherent(&acb->pdev->dev, acb->ioqueue_size, acb->dma_coherent2, acb->dma_coherent_handle2); break; } @@ -586,8 +586,8 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg; - acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32); - dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize, + acb->ioqueue_size = roundup(sizeof(struct MessageUnit_B), 32); + dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->ioqueue_size, &dma_coherent_handle, GFP_KERNEL); if (!dma_coherent) { pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no); @@ -616,8 +616,8 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_D: { struct MessageUnit_D *reg; - acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32); - dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize, + acb->ioqueue_size = roundup(sizeof(struct MessageUnit_D), 32); + dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->ioqueue_size, &dma_coherent_handle, GFP_KERNEL); if (!dma_coherent) { pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no); @@ -658,8 +658,8 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_E: { uint32_t completeQ_size; completeQ_size = sizeof(struct deliver_completeQ) * ARCMSR_MAX_HBE_DONEQUEUE + 128; - acb->roundup_ccbsize = roundup(completeQ_size, 32); - dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize, + acb->ioqueue_size = roundup(completeQ_size, 32); + dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->ioqueue_size, &dma_coherent_handle, GFP_KERNEL); if (!dma_coherent){ pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no); @@ -668,7 +668,7 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) acb->dma_coherent_handle2 = dma_coherent_handle; acb->dma_coherent2 = dma_coherent; acb->pCompletionQ = dma_coherent; - acb->completionQ_entry = acb->roundup_ccbsize / sizeof(struct deliver_completeQ); + acb->completionQ_entry = acb->ioqueue_size / sizeof(struct deliver_completeQ); acb->doneq_index = 0; } break; @@ -3787,7 +3787,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) cdb_phyaddr_hi32 = (uint32_t)((dma_coherent_handle >> 16) >> 16); writel(cdb_phyaddr, ®->msgcode_rwbuffer[5]); writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[6]); - writel(acb->roundup_ccbsize, ®->msgcode_rwbuffer[7]); + writel(acb->ioqueue_size, ®->msgcode_rwbuffer[7]); writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE; writel(acb->out_doorbell, ®->iobound_doorbell); -- cgit v1.2.3 From 609d08581a5a27e89a1b027e027caba3f013e8ce Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:27:20 +0800 Subject: scsi: arcmsr: Rename arcmsr_free_mu to arcmsr_free_io_queue From Ching Huang Rename arcmsr_free_mu to arcmsr_free_io_queue Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index f3a7855deab5..f831c13b444e 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -223,7 +223,7 @@ static struct pci_driver arcmsr_pci_driver = { **************************************************************************** */ -static void arcmsr_free_mu(struct AdapterControlBlock *acb) +static void arcmsr_free_io_queue(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_B: @@ -990,7 +990,7 @@ scsi_host_remove: free_ccb_pool: arcmsr_free_ccb_pool(acb); free_hbb_mu: - arcmsr_free_mu(acb); + arcmsr_free_io_queue(acb); unmap_pci_region: arcmsr_unmap_pciregion(acb); pci_release_regs: @@ -1500,7 +1500,7 @@ static void arcmsr_free_pcidev(struct AdapterControlBlock *acb) pdev = acb->pdev; arcmsr_free_irq(pdev, acb); arcmsr_free_ccb_pool(acb); - arcmsr_free_mu(acb); + arcmsr_free_io_queue(acb); arcmsr_unmap_pciregion(acb); pci_release_regions(pdev); scsi_host_put(host); @@ -1558,7 +1558,7 @@ static void arcmsr_remove(struct pci_dev *pdev) } arcmsr_free_irq(pdev, acb); arcmsr_free_ccb_pool(acb); - arcmsr_free_mu(acb); + arcmsr_free_io_queue(acb); arcmsr_unmap_pciregion(acb); pci_release_regions(pdev); scsi_host_put(host); -- cgit v1.2.3 From 222f1189b01ff9df27af7ab12cb028e7f43a7363 Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:31:00 +0800 Subject: scsi: arcmsr: Merge arcmsr_alloc_io_queue to arcmsr_alloc_ccb_pool From Ching Huang Merge arcmsr_alloc_io_queue to arcmsr_alloc_ccb_pool Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 127 ++++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index f831c13b444e..e1c75ca71753 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -576,6 +576,58 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) } } +static void arcmsr_hbaB_assign_regAddr(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = acb->pmuB; + + if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) { + reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203); + reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203); + reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203); + reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203); + } else { + reg->drv2iop_doorbell= MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL); + reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK); + reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL); + reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK); + } + reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER); + reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER); + reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER); +} + +static void arcmsr_hbaD_assign_regAddr(struct AdapterControlBlock *acb) +{ + struct MessageUnit_D *reg = acb->pmuD; + + reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID); + reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION); + reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK); + reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET); + reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST); + reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS); + reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE); + reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0); + reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1); + reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0); + reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1); + reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL); + reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL); + reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE); + reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW); + reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH); + reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER); + reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW); + reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH); + reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER); + reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER); + reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE); + reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE); + reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER); + reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER); + reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER); +} + static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) { bool rtn = true; @@ -585,7 +637,6 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg; acb->ioqueue_size = roundup(sizeof(struct MessageUnit_B), 32); dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->ioqueue_size, &dma_coherent_handle, GFP_KERNEL); @@ -595,27 +646,11 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) } acb->dma_coherent_handle2 = dma_coherent_handle; acb->dma_coherent2 = dma_coherent; - reg = (struct MessageUnit_B *)dma_coherent; - acb->pmuB = reg; - if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) { - reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203); - reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203); - reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203); - reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203); - } else { - reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL); - reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK); - reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL); - reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK); - } - reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER); - reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER); - reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER); + acb->pmuB = (struct MessageUnit_B *)dma_coherent; + arcmsr_hbaB_assign_regAddr(acb); } break; case ACB_ADAPTER_TYPE_D: { - struct MessageUnit_D *reg; - acb->ioqueue_size = roundup(sizeof(struct MessageUnit_D), 32); dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->ioqueue_size, &dma_coherent_handle, GFP_KERNEL); @@ -625,34 +660,8 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) } acb->dma_coherent_handle2 = dma_coherent_handle; acb->dma_coherent2 = dma_coherent; - reg = (struct MessageUnit_D *)dma_coherent; - acb->pmuD = reg; - reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID); - reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION); - reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK); - reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET); - reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST); - reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS); - reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE); - reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0); - reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1); - reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0); - reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1); - reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL); - reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL); - reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE); - reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW); - reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH); - reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER); - reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW); - reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH); - reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER); - reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER); - reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE); - reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE); - reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER); - reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER); - reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER); + acb->pmuD = (struct MessageUnit_D *)dma_coherent; + arcmsr_hbaD_assign_regAddr(acb); } break; case ACB_ADAPTER_TYPE_E: { @@ -706,6 +715,7 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) acb->host->sg_tablesize = max_sg_entrys; roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); acb->uncache_size = roundup_ccbsize * acb->maxFreeCCB; + acb->uncache_size += acb->ioqueue_size; dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); if(!dma_coherent){ printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error\n", acb->host->host_no); @@ -738,6 +748,23 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; } + acb->dma_coherent_handle2 = dma_coherent_handle; + acb->dma_coherent2 = ccb_tmp; + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_B: + acb->pmuB = (struct MessageUnit_B *)acb->dma_coherent2; + arcmsr_hbaB_assign_regAddr(acb); + break; + case ACB_ADAPTER_TYPE_D: + acb->pmuD = (struct MessageUnit_D *)acb->dma_coherent2; + arcmsr_hbaD_assign_regAddr(acb); + break; + case ACB_ADAPTER_TYPE_E: + acb->pCompletionQ = acb->dma_coherent2; + acb->completionQ_entry = acb->ioqueue_size / sizeof(struct deliver_completeQ); + acb->doneq_index = 0; + break; + } return 0; } @@ -959,9 +986,10 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) if(!error){ goto free_hbb_mu; } + arcmsr_free_io_queue(acb); error = arcmsr_alloc_ccb_pool(acb); if(error){ - goto free_hbb_mu; + goto unmap_pci_region; } error = scsi_add_host(host, &pdev->dev); if(error){ @@ -989,6 +1017,7 @@ scsi_host_remove: scsi_remove_host(host); free_ccb_pool: arcmsr_free_ccb_pool(acb); + goto unmap_pci_region; free_hbb_mu: arcmsr_free_io_queue(acb); unmap_pci_region: @@ -1500,7 +1529,6 @@ static void arcmsr_free_pcidev(struct AdapterControlBlock *acb) pdev = acb->pdev; arcmsr_free_irq(pdev, acb); arcmsr_free_ccb_pool(acb); - arcmsr_free_io_queue(acb); arcmsr_unmap_pciregion(acb); pci_release_regions(pdev); scsi_host_put(host); @@ -1558,7 +1586,6 @@ static void arcmsr_remove(struct pci_dev *pdev) } arcmsr_free_irq(pdev, acb); arcmsr_free_ccb_pool(acb); - arcmsr_free_io_queue(acb); arcmsr_unmap_pciregion(acb); pci_release_regions(pdev); scsi_host_put(host); -- cgit v1.2.3 From 7860a48686ff3a4d2ef9ed52d16c406b25148ba0 Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:34:58 +0800 Subject: scsi: arcmsr: Update arcmsr_alloc_ccb_pool for ccb buffer address above 4GB From Ching Huang Update arcmsr_alloc_ccb_pool for ccb buffer address above 4GB Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr.h | 9 +++++---- drivers/scsi/arcmsr/arcmsr_hba.c | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 256fe9a3ae1e..9041edc1af16 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -747,6 +747,7 @@ struct AdapterControlBlock uint32_t outbound_int_enable; uint32_t cdb_phyaddr_hi32; uint32_t reg_mu_acc_handle0; + uint64_t cdb_phyadd_hipart; spinlock_t eh_lock; spinlock_t ccblist_lock; spinlock_t postq_lock; @@ -855,11 +856,11 @@ struct AdapterControlBlock ******************************************************************************* */ struct CommandControlBlock{ - /*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/ + /*x32:sizeof struct_CCB=(64+60)byte, x64:sizeof struct_CCB=(64+60)byte*/ struct list_head list; /*x32: 8byte, x64: 16byte*/ struct scsi_cmnd *pcmd; /*8 bytes pointer of linux scsi command */ struct AdapterControlBlock *acb; /*x32: 4byte, x64: 8byte*/ - uint32_t cdb_phyaddr; /*x32: 4byte, x64: 4byte*/ + unsigned long cdb_phyaddr; /*x32: 4byte, x64: 8byte*/ uint32_t arc_cdb_size; /*x32:4byte,x64:4byte*/ uint16_t ccb_flags; /*x32: 2byte, x64: 2byte*/ #define CCB_FLAG_READ 0x0000 @@ -875,10 +876,10 @@ struct CommandControlBlock{ uint32_t smid; #if BITS_PER_LONG == 64 /* ======================512+64 bytes======================== */ - uint32_t reserved[4]; /*16 byte*/ + uint32_t reserved[3]; /*12 byte*/ #else /* ======================512+32 bytes======================== */ - // uint32_t reserved; /*4 byte*/ + uint32_t reserved[8]; /*32 byte*/ #endif /* ======================================================= */ struct ARCMSR_CDB arcmsr_cdb; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index e1c75ca71753..5353dbbcb629 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -694,11 +694,11 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) dma_addr_t dma_coherent_handle; struct CommandControlBlock *ccb_tmp; int i = 0, j = 0; - dma_addr_t cdb_phyaddr; + unsigned long cdb_phyaddr, next_ccb_phy; unsigned long roundup_ccbsize; unsigned long max_xfer_len; unsigned long max_sg_entrys; - uint32_t firm_config_version; + uint32_t firm_config_version, curr_phy_upper32; for (i = 0; i < ARCMSR_MAX_TARGETID; i++) for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) @@ -726,9 +726,10 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) memset(dma_coherent, 0, acb->uncache_size); acb->ccbsize = roundup_ccbsize; ccb_tmp = dma_coherent; + curr_phy_upper32 = upper_32_bits(dma_coherent_handle); acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; for(i = 0; i < acb->maxFreeCCB; i++){ - cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); + cdb_phyaddr = (unsigned long)dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: case ACB_ADAPTER_TYPE_B: @@ -744,9 +745,16 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) ccb_tmp->acb = acb; ccb_tmp->smid = (u32)i << 16; INIT_LIST_HEAD(&ccb_tmp->list); - list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); + next_ccb_phy = dma_coherent_handle + roundup_ccbsize; + if (upper_32_bits(next_ccb_phy) != curr_phy_upper32) { + acb->maxFreeCCB = i; + acb->host->can_queue = i; + break; + } + else + list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); - dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; + dma_coherent_handle = next_ccb_phy; } acb->dma_coherent_handle2 = dma_coherent_handle; acb->dma_coherent2 = ccb_tmp; @@ -3701,6 +3709,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) cdb_phyaddr = lower_32_bits(dma_coherent_handle); cdb_phyaddr_hi32 = upper_32_bits(dma_coherent_handle); acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32; + acb->cdb_phyadd_hipart = ((uint64_t)cdb_phyaddr_hi32) << 32; /* *********************************************************************** ** if adapter type B, set window of "post command Q" -- cgit v1.2.3 From 9e386a55e07253f1361223ecf08e78640463032a Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:43:15 +0800 Subject: scsi: arcmsr: Update ACB_ADAPTER_TYPE_A for >4GB ccb addressing From Ching Huang Update ACB_ADAPTER_TYPE_A for >4GB ccb addressing Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 5353dbbcb629..2ff1c9ae63d6 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1382,10 +1382,12 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct Comma static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) { int i = 0; - uint32_t flag_ccb, ccb_cdb_phy; + uint32_t flag_ccb; struct ARCMSR_CDB *pARCMSR_CDB; bool error; struct CommandControlBlock *pCCB; + unsigned long ccb_cdb_phy, cdb_phy_hipart; + switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { @@ -1397,7 +1399,10 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ while(((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && (i++ < acb->maxOutstanding)) { - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ + ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff; + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; arcmsr_drain_donequeue(acb, pCCB, error); @@ -2333,8 +2338,13 @@ static void arcmsr_hbaA_postqueue_isr(struct AdapterControlBlock *acb) struct ARCMSR_CDB *pARCMSR_CDB; struct CommandControlBlock *pCCB; bool error; + unsigned long cdb_phy_addr; + while ((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) { - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ + cdb_phy_addr = (flag_ccb << 5) & 0xffffffff; + if (acb->cdb_phyadd_hipart) + cdb_phy_addr = cdb_phy_addr | acb->cdb_phyadd_hipart; + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + cdb_phy_addr); pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; arcmsr_drain_donequeue(acb, pCCB, error); @@ -3258,7 +3268,9 @@ static int arcmsr_hbaA_polling_ccbdone(struct AdapterControlBlock *acb, uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; int rtn; bool error; - polling_hba_ccb_retry: + unsigned long ccb_cdb_phy; + +polling_hba_ccb_retry: poll_count++; outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ @@ -3276,7 +3288,10 @@ static int arcmsr_hbaA_polling_ccbdone(struct AdapterControlBlock *acb, goto polling_hba_ccb_retry; } } - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); + ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff; + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); poll_ccb_done |= (ccb == poll_ccb) ? 1 : 0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { -- cgit v1.2.3 From e66764f276e9dc5985ad1fbb32f7bde24a478b39 Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:45:46 +0800 Subject: scsi: arcmsr: Update ACB_ADAPTER_TYPE_B for >4GB ccb addressing From Ching Huang Update ACB_ADAPTER_TYPE_B for >4GB ccb addressing Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 2ff1c9ae63d6..3d2727c0321b 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1418,7 +1418,10 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) flag_ccb = reg->done_qbuffer[i]; if (flag_ccb != 0) { reg->done_qbuffer[i] = 0; - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ + ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff; + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; arcmsr_drain_donequeue(acb, pCCB, error); @@ -2358,13 +2361,18 @@ static void arcmsr_hbaB_postqueue_isr(struct AdapterControlBlock *acb) struct ARCMSR_CDB *pARCMSR_CDB; struct CommandControlBlock *pCCB; bool error; + unsigned long cdb_phy_addr; + index = reg->doneq_index; while ((flag_ccb = reg->done_qbuffer[index]) != 0) { - reg->done_qbuffer[index] = 0; - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ + cdb_phy_addr = (flag_ccb << 5) & 0xffffffff; + if (acb->cdb_phyadd_hipart) + cdb_phy_addr = cdb_phy_addr | acb->cdb_phyadd_hipart; + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + cdb_phy_addr); pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; arcmsr_drain_donequeue(acb, pCCB, error); + reg->done_qbuffer[index] = 0; index++; index %= ARCMSR_MAX_HBB_POSTQUEUE; reg->doneq_index = index; @@ -3329,8 +3337,9 @@ static int arcmsr_hbaB_polling_ccbdone(struct AdapterControlBlock *acb, uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; int index, rtn; bool error; - polling_hbb_ccb_retry: + unsigned long ccb_cdb_phy; +polling_hbb_ccb_retry: poll_count++; /* clear doorbell interrupt */ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); @@ -3356,7 +3365,10 @@ static int arcmsr_hbaB_polling_ccbdone(struct AdapterControlBlock *acb, index %= ARCMSR_MAX_HBB_POSTQUEUE; reg->doneq_index = index; /* check if command done with no error*/ - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); + ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff; + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); poll_ccb_done |= (ccb == poll_ccb) ? 1 : 0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { -- cgit v1.2.3 From c71ec5511b14dcf90141d334fb5277934b496d14 Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:48:16 +0800 Subject: scsi: arcmsr: Update ACB_ADAPTER_TYPE_C for >4GB ccb addressing From Ching Huang Update ACB_ADAPTER_TYPE_C for >4GB ccb addressing Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 3d2727c0321b..39f3cd066034 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1438,7 +1438,9 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) /*need to do*/ flag_ccb = readl(®->outbound_queueport_low); ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+ccb_cdb_phy);/*frame must be 32 bytes aligned*/ + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; arcmsr_drain_donequeue(acb, pCCB, error); @@ -1786,12 +1788,8 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size; ccb_post_stamp = (cdb_phyaddr | ((arc_cdb_size - 1) >> 6) | 1); - if (acb->cdb_phyaddr_hi32) { - writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high); - writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); - } else { - writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); - } + writel(upper_32_bits(ccb->cdb_phyaddr), &phbcmu->inbound_queueport_high); + writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); } break; case ACB_ADAPTER_TYPE_D: { @@ -2384,7 +2382,8 @@ static void arcmsr_hbaC_postqueue_isr(struct AdapterControlBlock *acb) struct MessageUnit_C __iomem *phbcmu; struct ARCMSR_CDB *arcmsr_cdb; struct CommandControlBlock *ccb; - uint32_t flag_ccb, ccb_cdb_phy, throttling = 0; + uint32_t flag_ccb, throttling = 0; + unsigned long ccb_cdb_phy; int error; phbcmu = acb->pmuC; @@ -2394,6 +2393,8 @@ static void arcmsr_hbaC_postqueue_isr(struct AdapterControlBlock *acb) while ((flag_ccb = readl(&phbcmu->outbound_queueport_low)) != 0xFFFFFFFF) { ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); ccb = container_of(arcmsr_cdb, struct CommandControlBlock, @@ -3401,12 +3402,14 @@ static int arcmsr_hbaC_polling_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { struct MessageUnit_C __iomem *reg = acb->pmuC; - uint32_t flag_ccb, ccb_cdb_phy; + uint32_t flag_ccb; struct ARCMSR_CDB *arcmsr_cdb; bool error; struct CommandControlBlock *pCCB; uint32_t poll_ccb_done = 0, poll_count = 0; int rtn; + unsigned long ccb_cdb_phy; + polling_hbc_ccb_retry: poll_count++; while (1) { @@ -3425,7 +3428,9 @@ polling_hbc_ccb_retry: } flag_ccb = readl(®->outbound_queueport_low); ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/ + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0; /* check ifcommand done with no error*/ @@ -3801,7 +3806,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) } break; case ACB_ADAPTER_TYPE_C: { - if (cdb_phyaddr_hi32 != 0) { struct MessageUnit_C __iomem *reg = acb->pmuC; printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n", @@ -3816,7 +3820,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) return 1; } } - } break; case ACB_ADAPTER_TYPE_D: { uint32_t __iomem *rwbuffer; -- cgit v1.2.3 From a36ade416db7823eb4af9b29729ba3d4a3bb1304 Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:51:14 +0800 Subject: scsi: arcmsr: Update ACB_ADAPTER_TYPE_D for >4GB ccb addressing From Ching Huang Update ACB_ADAPTER_TYPE_D for >4gb ccb addressing Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 39f3cd066034..8cc21347a378 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1468,9 +1468,13 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) ((toggle ^ 0x4000) + 1); doneq_index = pmu->doneq_index; spin_unlock_irqrestore(&acb->doneq_lock, flags); + cdb_phy_hipart = pmu->done_qbuffer[doneq_index & + 0xFFF].addressHigh; addressLow = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow; ccb_cdb_phy = (addressLow & 0xFFFFFFF0); + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; pARCMSR_CDB = (struct ARCMSR_CDB *) (acb->vir2phy_offset + ccb_cdb_phy); pCCB = container_of(pARCMSR_CDB, @@ -1802,8 +1806,8 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr spin_lock_irqsave(&acb->postq_lock, flags); postq_index = pmu->postq_index; pinbound_srb = (struct InBound_SRB *)&(pmu->post_qbuffer[postq_index & 0xFF]); - pinbound_srb->addressHigh = dma_addr_hi32(cdb_phyaddr); - pinbound_srb->addressLow = dma_addr_lo32(cdb_phyaddr); + pinbound_srb->addressHigh = upper_32_bits(ccb->cdb_phyaddr); + pinbound_srb->addressLow = cdb_phyaddr; pinbound_srb->length = ccb->arc_cdb_size >> 2; arcmsr_cdb->msgContext = dma_addr_lo32(cdb_phyaddr); toggle = postq_index & 0x4000; @@ -2415,12 +2419,12 @@ static void arcmsr_hbaC_postqueue_isr(struct AdapterControlBlock *acb) static void arcmsr_hbaD_postqueue_isr(struct AdapterControlBlock *acb) { u32 outbound_write_pointer, doneq_index, index_stripped, toggle; - uint32_t addressLow, ccb_cdb_phy; + uint32_t addressLow; int error; struct MessageUnit_D *pmu; struct ARCMSR_CDB *arcmsr_cdb; struct CommandControlBlock *ccb; - unsigned long flags; + unsigned long flags, ccb_cdb_phy, cdb_phy_hipart; spin_lock_irqsave(&acb->doneq_lock, flags); pmu = acb->pmuD; @@ -2434,9 +2438,13 @@ static void arcmsr_hbaD_postqueue_isr(struct AdapterControlBlock *acb) pmu->doneq_index = index_stripped ? (index_stripped | toggle) : ((toggle ^ 0x4000) + 1); doneq_index = pmu->doneq_index; + cdb_phy_hipart = pmu->done_qbuffer[doneq_index & + 0xFFF].addressHigh; addressLow = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow; ccb_cdb_phy = (addressLow & 0xFFFFFFF0); + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); ccb = container_of(arcmsr_cdb, @@ -3464,9 +3472,9 @@ static int arcmsr_hbaD_polling_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { bool error; - uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb, ccb_cdb_phy; + uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb; int rtn, doneq_index, index_stripped, outbound_write_pointer, toggle; - unsigned long flags; + unsigned long flags, ccb_cdb_phy, cdb_phy_hipart; struct ARCMSR_CDB *arcmsr_cdb; struct CommandControlBlock *pCCB; struct MessageUnit_D *pmu = acb->pmuD; @@ -3498,8 +3506,12 @@ polling_hbaD_ccb_retry: ((toggle ^ 0x4000) + 1); doneq_index = pmu->doneq_index; spin_unlock_irqrestore(&acb->doneq_lock, flags); + cdb_phy_hipart = pmu->done_qbuffer[doneq_index & + 0xFFF].addressHigh; flag_ccb = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow; ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); + if (acb->cdb_phyadd_hipart) + ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart; arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, -- cgit v1.2.3 From 7ec7261f66df089beab170441ecb38c5659444ec Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:53:44 +0800 Subject: scsi: arcmsr: Add an option of set dma_mask_64 for ACB_ADAPTER_TYPE_A From Ching Huang Add an option of set dma_mask_64 for ACB_ADAPTER_TYPE_A Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 8cc21347a378..45f1374294eb 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -91,6 +91,10 @@ static int cmd_per_lun = ARCMSR_DEFAULT_CMD_PERLUN; module_param(cmd_per_lun, int, S_IRUGO); MODULE_PARM_DESC(cmd_per_lun, " device queue depth(1 ~ 128), default is 32"); +static int dma_mask_64 = 0; +module_param(dma_mask_64, int, S_IRUGO); +MODULE_PARM_DESC(dma_mask_64, " set DMA mask to 64 bits(0 ~ 1), dma_mask_64=1(64 bits), =0(32 bits)"); + static int set_date_time = 0; module_param(set_date_time, int, S_IRUGO); MODULE_PARM_DESC(set_date_time, " send date, time to iop(0 ~ 1), set_date_time=1(enable), default(=0) is disable"); -- cgit v1.2.3 From 1d120c6183aa3e53d3fb7fa094db5aa902381d50 Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:56:34 +0800 Subject: scsi: arcmsr: Separate 'set dma mask' as a function From Ching Huang Separate 'set dma mask' as a function Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 51 +++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 45f1374294eb..30dff6c3c2d4 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -927,6 +927,31 @@ static void arcmsr_init_set_datetime_timer(struct AdapterControlBlock *pacb) add_timer(&pacb->refresh_timer); } +static int arcmsr_set_dma_mask(struct AdapterControlBlock *acb) +{ + struct pci_dev *pcidev = acb->pdev; + + if (IS_DMA64) { + if (((acb->adapter_type == ACB_ADAPTER_TYPE_A) && !dma_mask_64) || + dma_set_mask(&pcidev->dev, DMA_BIT_MASK(64))) + goto dma32; + if (dma_set_coherent_mask(&pcidev->dev, DMA_BIT_MASK(64)) || + dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(64))) { + printk("arcmsr: set DMA 64 mask failed\n"); + return -ENXIO; + } + } else { +dma32: + if (dma_set_mask(&pcidev->dev, DMA_BIT_MASK(32)) || + dma_set_coherent_mask(&pcidev->dev, DMA_BIT_MASK(32)) || + dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32))) { + printk("arcmsr: set DMA 32-bit mask failed\n"); + return -ENXIO; + } + } + return 0; +} + static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct Scsi_Host *host; @@ -941,22 +966,15 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) if(!host){ goto pci_disable_dev; } - error = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); - if(error){ - error = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if(error){ - printk(KERN_WARNING - "scsi%d: No suitable DMA mask available\n", - host->host_no); - goto scsi_host_release; - } - } init_waitqueue_head(&wait_q); bus = pdev->bus->number; dev_fun = pdev->devfn; acb = (struct AdapterControlBlock *) host->hostdata; memset(acb,0,sizeof(struct AdapterControlBlock)); acb->pdev = pdev; + acb->adapter_type = id->driver_data; + if (arcmsr_set_dma_mask(acb)) + goto scsi_host_release; acb->host = host; host->max_lun = ARCMSR_MAX_TARGETLUN; host->max_id = ARCMSR_MAX_TARGETID; /*16:8*/ @@ -986,7 +1004,6 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) ACB_F_MESSAGE_WQBUFFER_READED); acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; INIT_LIST_HEAD(&acb->ccb_free_list); - acb->adapter_type = id->driver_data; error = arcmsr_remap_pciregion(acb); if(!error){ goto pci_release_regs; @@ -1077,7 +1094,6 @@ static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state) static int arcmsr_resume(struct pci_dev *pdev) { - int error; struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata; @@ -1089,15 +1105,8 @@ static int arcmsr_resume(struct pci_dev *pdev) pr_warn("%s: pci_enable_device error\n", __func__); return -ENODEV; } - error = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (error) { - error = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (error) { - pr_warn("scsi%d: No suitable DMA mask available\n", - host->host_no); - goto controller_unregister; - } - } + if (arcmsr_set_dma_mask(acb)) + goto controller_unregister; pci_set_master(pdev); if (arcmsr_request_irq(pdev, acb) == FAILED) goto controller_stop; -- cgit v1.2.3 From afdda87852efc6d8fa55b17b73f842f13c8f8f0a Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 16:59:48 +0800 Subject: scsi: arcmsr: Fix suspend/resume of ACB_ADAPTER_TYPE_B From Ching Huang Fix suspend/resume of ACB_ADAPTER_TYPE_B Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 30dff6c3c2d4..9f85d5abbb0c 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1110,12 +1110,21 @@ static int arcmsr_resume(struct pci_dev *pdev) pci_set_master(pdev); if (arcmsr_request_irq(pdev, acb) == FAILED) goto controller_stop; - if (acb->adapter_type == ACB_ADAPTER_TYPE_E) { + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = acb->pmuB; + reg->post_qbuffer[0] = 0; + reg->postq_index = 0; + reg->doneq_index = 0; + break; + } + case ACB_ADAPTER_TYPE_E: writel(0, &acb->pmuE->host_int_status); writel(ARCMSR_HBEMU_DOORBELL_SYNC, &acb->pmuE->iobound_doorbell); acb->in_doorbell = 0; acb->out_doorbell = 0; acb->doneq_index = 0; + break; } arcmsr_iop_init(acb); arcmsr_init_get_devmap_timer(acb); -- cgit v1.2.3 From ad796f790cc2db13d3899107b19aae4b439a2f9b Mon Sep 17 00:00:00 2001 From: Ching Huang Date: Wed, 19 Dec 2018 17:02:08 +0800 Subject: scsi: arcmsr: Update driver version to v1.40.00.10-20181217 From Ching Huang Update driver version to v1.40.00.10-20181217 Signed-off-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 9041edc1af16..a94c513a57d8 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -49,7 +49,7 @@ struct device_attribute; #define ARCMSR_MAX_OUTSTANDING_CMD 1024 #define ARCMSR_DEFAULT_OUTSTANDING_CMD 128 #define ARCMSR_MIN_OUTSTANDING_CMD 32 -#define ARCMSR_DRIVER_VERSION "v1.40.00.09-20180709" +#define ARCMSR_DRIVER_VERSION "v1.40.00.10-20181217" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 -- cgit v1.2.3 From ef63464bcf8feaa793e1aee4d3d186dfd1fff05f Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 19 Dec 2018 23:56:39 +0800 Subject: scsi: hisi_sas: Create root and device debugfs directories This patch creates root directory at hisi_sas_init() and generates device directory when we probe device driver. And we remove the root directory at hisi_sas_exit(), but recursively delete device directory when we remove device driver. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 9 +++++++++ drivers/scsi/hisi_sas/hisi_sas_main.c | 27 +++++++++++++++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 5 +++++ 3 files changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index af291947a54d..3ad87462593b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -332,6 +333,8 @@ struct hisi_hba { u32 phy_state; u32 intr_coal_ticks; /* Time of interrupt coalesce in us */ u32 intr_coal_count; /* Interrupt count to coalesce */ + + struct dentry *debugfs_dir; }; /* Generic HW DMA host memory structures */ @@ -461,6 +464,10 @@ struct hisi_sas_slot_buf_table { }; extern struct scsi_transport_template *hisi_sas_stt; + +extern bool hisi_sas_debugfs_enable; +extern struct dentry *hisi_sas_debugfs_dir; + extern void hisi_sas_stop_phys(struct hisi_hba *hisi_hba); extern int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost); extern void hisi_sas_free(struct hisi_hba *hisi_hba); @@ -493,4 +500,6 @@ extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba); extern u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max); extern void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba); extern void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba); +extern void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba); +extern void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba); #endif diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index eed7fc5b3389..919cd3bd746a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2457,6 +2457,23 @@ err_out_ha: } EXPORT_SYMBOL_GPL(hisi_sas_probe); +struct dentry *hisi_sas_debugfs_dir; + +void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + + hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), + hisi_sas_debugfs_dir); +} +EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init); + +void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba) +{ + debugfs_remove_recursive(hisi_hba->debugfs_dir); +} +EXPORT_SYMBOL_GPL(hisi_sas_debugfs_exit); + int hisi_sas_remove(struct platform_device *pdev) { struct sas_ha_struct *sha = platform_get_drvdata(pdev); @@ -2475,18 +2492,28 @@ int hisi_sas_remove(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(hisi_sas_remove); +bool hisi_sas_debugfs_enable; +EXPORT_SYMBOL_GPL(hisi_sas_debugfs_enable); +module_param_named(debugfs_enable, hisi_sas_debugfs_enable, bool, 0444); +MODULE_PARM_DESC(hisi_sas_debugfs_enable, "Enable driver debugfs (default disabled)"); + static __init int hisi_sas_init(void) { hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops); if (!hisi_sas_stt) return -ENOMEM; + if (hisi_sas_debugfs_enable) + hisi_sas_debugfs_dir = debugfs_create_dir("hisi_sas", NULL); + return 0; } static __exit void hisi_sas_exit(void) { sas_release_transport(hisi_sas_stt); + + debugfs_remove(hisi_sas_debugfs_dir); } module_init(hisi_sas_init); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index e2420a810e99..a7d9651d1ec3 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2507,6 +2507,9 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) sha->sas_port[i] = &hisi_hba->port[i].sas_port; } + if (hisi_sas_debugfs_enable) + hisi_sas_debugfs_init(hisi_hba); + rc = scsi_add_host(shost, dev); if (rc) goto err_out_ha; @@ -2565,6 +2568,8 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) struct hisi_hba *hisi_hba = sha->lldd_ha; struct Scsi_Host *shost = sha->core.shost; + hisi_sas_debugfs_exit(hisi_hba); + if (timer_pending(&hisi_hba->timer)) del_timer(&hisi_hba->timer); -- cgit v1.2.3 From eb1c2b72b7694c984d520300c901f5fc1fa8ea9e Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 19 Dec 2018 23:56:40 +0800 Subject: scsi: hisi_sas: Alloc debugfs snapshot buffer memory for all registers This patch allocates snapshot memory for global reg, port regs, CQ, DQ, IOST, ITCT. When we fail to allocate memory for some registers, we free the memory and set hisi_sas_debugfs_enable as 0 to stop loading debugfs from running. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 15 +++++++ drivers/scsi/hisi_sas/hisi_sas_main.c | 76 ++++++++++++++++++++++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 8 ++++ 3 files changed, 99 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 3ad87462593b..eca7e474ea01 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -221,6 +221,10 @@ struct hisi_sas_slot { u16 idx; }; +struct hisi_sas_debugfs_reg { + int count; +}; + struct hisi_sas_hw { int (*hw_init)(struct hisi_hba *hisi_hba); void (*setup_itct)(struct hisi_hba *hisi_hba, @@ -265,6 +269,9 @@ struct hisi_sas_hw { int max_command_entries; int complete_hdr_size; struct scsi_host_template *sht; + + const struct hisi_sas_debugfs_reg *debugfs_reg_global; + const struct hisi_sas_debugfs_reg *debugfs_reg_port; }; struct hisi_hba { @@ -334,6 +341,14 @@ struct hisi_hba { u32 intr_coal_ticks; /* Time of interrupt coalesce in us */ u32 intr_coal_count; /* Interrupt count to coalesce */ + /* debugfs memories */ + void *debugfs_global_reg; + void *debugfs_port_reg[HISI_SAS_MAX_PHYS]; + void *debugfs_complete_hdr[HISI_SAS_MAX_QUEUES]; + struct hisi_sas_cmd_hdr *debugfs_cmd_hdr[HISI_SAS_MAX_QUEUES]; + struct hisi_sas_iost *debugfs_iost; + struct hisi_sas_itct *debugfs_itct; + struct dentry *debugfs_dir; }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 919cd3bd746a..0b0dbaabcce8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2461,10 +2461,86 @@ struct dentry *hisi_sas_debugfs_dir; void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) { + int max_command_entries = hisi_hba->hw->max_command_entries; struct device *dev = hisi_hba->dev; + int p, i, c, d; + size_t sz; hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), hisi_sas_debugfs_dir); + + if (!hisi_hba->debugfs_dir) + return; + + /* Alloc buffer for global */ + sz = hisi_hba->hw->debugfs_reg_global->count * 4; + hisi_hba->debugfs_global_reg = + devm_kmalloc(dev, sz, GFP_KERNEL); + + if (!hisi_hba->debugfs_global_reg) + goto fail_global; + + /* Alloc buffer for port */ + sz = hisi_hba->hw->debugfs_reg_port->count * 4; + for (p = 0; p < hisi_hba->n_phy; p++) { + hisi_hba->debugfs_port_reg[p] = + devm_kmalloc(dev, sz, GFP_KERNEL); + + if (!hisi_hba->debugfs_port_reg[p]) + goto fail_port; + } + + /* Alloc buffer for cq */ + sz = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; + for (c = 0; c < hisi_hba->queue_count; c++) { + hisi_hba->debugfs_complete_hdr[c] = + devm_kmalloc(dev, sz, GFP_KERNEL); + + if (!hisi_hba->debugfs_complete_hdr[c]) + goto fail_cq; + } + + /* Alloc buffer for dq */ + sz = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; + for (d = 0; d < hisi_hba->queue_count; d++) { + hisi_hba->debugfs_cmd_hdr[d] = + devm_kmalloc(dev, sz, GFP_KERNEL); + + if (!hisi_hba->debugfs_cmd_hdr[d]) + goto fail_iost_dq; + } + + /* Alloc buffer for iost */ + sz = max_command_entries * sizeof(struct hisi_sas_iost); + + hisi_hba->debugfs_iost = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_iost) + goto fail_iost_dq; + + /* Alloc buffer for itct */ + /* New memory allocation must be locate before itct */ + sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); + + hisi_hba->debugfs_itct = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_itct) + goto fail_itct; + + return; +fail_itct: + devm_kfree(dev, hisi_hba->debugfs_iost); +fail_iost_dq: + for (i = 0; i < d; i++) + devm_kfree(dev, hisi_hba->debugfs_cmd_hdr[i]); +fail_cq: + for (i = 0; i < c; i++) + devm_kfree(dev, hisi_hba->debugfs_complete_hdr[i]); +fail_port: + for (i = 0; i < p; i++) + devm_kfree(dev, hisi_hba->debugfs_port_reg[i]); + devm_kfree(dev, hisi_hba->debugfs_global_reg); +fail_global: + debugfs_remove_recursive(hisi_hba->debugfs_dir); + dev_dbg(dev, "failed to init debugfs!\n"); } EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index a7d9651d1ec3..c1b47022d6fd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2332,6 +2332,12 @@ static struct device_attribute *host_attrs_v3_hw[] = { NULL }; +static const struct hisi_sas_debugfs_reg debugfs_port_reg = { +}; + +static const struct hisi_sas_debugfs_reg debugfs_global_reg = { +}; + static struct scsi_host_template sht_v3_hw = { .name = DRV_NAME, .module = THIS_MODULE, @@ -2380,6 +2386,8 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { .get_events = phy_get_events_v3_hw, .write_gpio = write_gpio_v3_hw, .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw, + .debugfs_reg_global = &debugfs_global_reg, + .debugfs_reg_port = &debugfs_port_reg, }; static struct Scsi_Host * -- cgit v1.2.3 From 49159a5e4175f9f7a5149e7e27f583de04e934c2 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 19 Dec 2018 23:56:41 +0800 Subject: scsi: hisi_sas: Take debugfs snapshot for all regs This patch takes snapshot for global regs, port regs, CQ, DQ, IOST, ITCT. Add code for snapshot trig and generate dump directory. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 15 +++- drivers/scsi/hisi_sas/hisi_sas_main.c | 125 +++++++++++++++++++++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 9 ++- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 37 +++++++++- 4 files changed, 180 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index eca7e474ea01..3b5fd6d638f0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -223,6 +223,12 @@ struct hisi_sas_slot { struct hisi_sas_debugfs_reg { int count; + int base_off; + union { + u32 (*read_global_reg)(struct hisi_hba *hisi_hba, u32 off); + u32 (*read_port_reg)(struct hisi_hba *hisi_hba, int port, + u32 off); + }; }; struct hisi_sas_hw { @@ -264,8 +270,10 @@ struct hisi_sas_hw { u32 (*get_phys_state)(struct hisi_hba *hisi_hba); int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type, u8 reg_index, u8 reg_count, u8 *write_data); - void (*wait_cmds_complete_timeout)(struct hisi_hba *hisi_hba, - int delay_ms, int timeout_ms); + int (*wait_cmds_complete_timeout)(struct hisi_hba *hisi_hba, + int delay_ms, int timeout_ms); + void (*snapshot_prepare)(struct hisi_hba *hisi_hba); + void (*snapshot_restore)(struct hisi_hba *hisi_hba); int max_command_entries; int complete_hdr_size; struct scsi_host_template *sht; @@ -337,6 +345,7 @@ struct hisi_hba { const struct hisi_sas_hw *hw; /* Low level hw interface */ unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; struct work_struct rst_work; + struct work_struct debugfs_work; u32 phy_state; u32 intr_coal_ticks; /* Time of interrupt coalesce in us */ u32 intr_coal_count; /* Interrupt count to coalesce */ @@ -350,6 +359,7 @@ struct hisi_hba { struct hisi_sas_itct *debugfs_itct; struct dentry *debugfs_dir; + struct dentry *debugfs_dump_dentry; }; /* Generic HW DMA host memory structures */ @@ -517,4 +527,5 @@ extern void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba); extern void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba); extern void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba); extern void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba); +extern void hisi_sas_debugfs_work_handler(struct work_struct *work); #endif diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 0b0dbaabcce8..742f71a8412a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1429,6 +1429,10 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) struct Scsi_Host *shost = hisi_hba->shost; int rc; + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct && + !hisi_hba->debugfs_dump_dentry) + queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); + if (!hisi_hba->hw->soft_reset) return -1; @@ -1923,6 +1927,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, slot->task = NULL; } dev_err(dev, "internal task abort: timeout and not done.\n"); + res = -EIO; goto exit; } else @@ -2459,6 +2464,126 @@ EXPORT_SYMBOL_GPL(hisi_sas_probe); struct dentry *hisi_sas_debugfs_dir; +static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba) +{ + int queue_entry_size = hisi_hba->hw->complete_hdr_size; + int i; + + for (i = 0; i < hisi_hba->queue_count; i++) + memcpy(hisi_hba->debugfs_complete_hdr[i], + hisi_hba->complete_hdr[i], + HISI_SAS_QUEUE_SLOTS * queue_entry_size); +} + +static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba) +{ + int queue_entry_size = hisi_hba->hw->complete_hdr_size; + int i; + + for (i = 0; i < hisi_hba->queue_count; i++) + memcpy(hisi_hba->debugfs_cmd_hdr[i], + hisi_hba->cmd_hdr[i], + HISI_SAS_QUEUE_SLOTS * queue_entry_size); +} + +static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) +{ + const struct hisi_sas_debugfs_reg *port = + hisi_hba->hw->debugfs_reg_port; + int i, phy_cnt; + u32 offset; + u32 *databuf; + + for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { + databuf = (u32 *)hisi_hba->debugfs_port_reg[phy_cnt]; + for (i = 0; i < port->count; i++, databuf++) { + offset = port->base_off + 4 * i; + *databuf = port->read_port_reg(hisi_hba, phy_cnt, + offset); + } + } +} + +static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) +{ + u32 *databuf = (u32 *)hisi_hba->debugfs_global_reg; + const struct hisi_sas_debugfs_reg *global = + hisi_hba->hw->debugfs_reg_global; + int i; + + for (i = 0; i < global->count; i++, databuf++) + *databuf = global->read_global_reg(hisi_hba, 4 * i); +} + +static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) +{ + void *databuf = hisi_hba->debugfs_itct; + struct hisi_sas_itct *itct; + int i; + + itct = hisi_hba->itct; + + for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { + memcpy(databuf, itct, sizeof(struct hisi_sas_itct)); + databuf += sizeof(struct hisi_sas_itct); + } +} + +static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) +{ + int max_command_entries = hisi_hba->hw->max_command_entries; + void *databuf = hisi_hba->debugfs_iost; + struct hisi_sas_iost *iost; + int i; + + iost = hisi_hba->iost; + + for (i = 0; i < max_command_entries; i++, iost++) { + memcpy(databuf, iost, sizeof(struct hisi_sas_iost)); + databuf += sizeof(struct hisi_sas_iost); + } +} + +static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) +{ + struct dentry *dump_dentry; + + /* Create dump dir inside device dir */ + dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); + if (!dump_dentry) + goto fail; + + hisi_hba->debugfs_dump_dentry = dump_dentry; + return; +fail: + debugfs_remove_recursive(hisi_hba->debugfs_dir); +} + +static void hisi_sas_debugfs_snapshot_regs(struct hisi_hba *hisi_hba) +{ + hisi_hba->hw->snapshot_prepare(hisi_hba); + + hisi_sas_debugfs_snapshot_global_reg(hisi_hba); + hisi_sas_debugfs_snapshot_port_reg(hisi_hba); + hisi_sas_debugfs_snapshot_cq_reg(hisi_hba); + hisi_sas_debugfs_snapshot_dq_reg(hisi_hba); + hisi_sas_debugfs_snapshot_itct_reg(hisi_hba); + hisi_sas_debugfs_snapshot_iost_reg(hisi_hba); + + hisi_sas_debugfs_create_files(hisi_hba); + + hisi_hba->hw->snapshot_restore(hisi_hba); +} + +void hisi_sas_debugfs_work_handler(struct work_struct *work) +{ + struct hisi_hba *hisi_hba = + container_of(work, struct hisi_hba, debugfs_work); + + hisi_sas_debugfs_snapshot_regs(hisi_hba); +} +EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler); + void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) { int max_command_entries = hisi_hba->hw->max_command_entries; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index c8ebff3ba559..5c4b8dff4c10 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -3542,8 +3542,8 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, return 0; } -static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, - int delay_ms, int timeout_ms) +static int wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, + int delay_ms, int timeout_ms) { struct device *dev = hisi_hba->dev; int entries, entries_old = 0, time; @@ -3557,7 +3557,12 @@ static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, msleep(delay_ms); } + if (time >= timeout_ms) + return -ETIMEDOUT; + dev_dbg(dev, "wait commands complete %dms\n", time); + + return 0; } static struct device_attribute *host_attrs_v2_hw[] = { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index c1b47022d6fd..5727c265abc7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2201,8 +2201,8 @@ static int write_gpio_v3_hw(struct hisi_hba *hisi_hba, u8 reg_type, return 0; } -static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, - int delay_ms, int timeout_ms) +static int wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, + int delay_ms, int timeout_ms) { struct device *dev = hisi_hba->dev; int entries, entries_old = 0, time; @@ -2216,7 +2216,12 @@ static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, msleep(delay_ms); } + if (time >= timeout_ms) + return -ETIMEDOUT; + dev_dbg(dev, "wait commands complete %dms\n", time); + + return 0; } static ssize_t intr_conv_v3_hw_show(struct device *dev, @@ -2333,11 +2338,36 @@ static struct device_attribute *host_attrs_v3_hw[] = { }; static const struct hisi_sas_debugfs_reg debugfs_port_reg = { + .base_off = PORT_BASE, + .read_port_reg = hisi_sas_phy_read32, }; static const struct hisi_sas_debugfs_reg debugfs_global_reg = { + .read_global_reg = hisi_sas_read32, }; +static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + + set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + + hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0); + + if (wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000) == -ETIMEDOUT) + dev_dbg(dev, "Wait commands complete timeout!\n"); + + hisi_sas_kill_tasklets(hisi_hba); +} + +static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba) +{ + hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, + (u32)((1ULL << hisi_hba->queue_count) - 1)); + + clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); +} + static struct scsi_host_template sht_v3_hw = { .name = DRV_NAME, .module = THIS_MODULE, @@ -2388,6 +2418,8 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw, .debugfs_reg_global = &debugfs_global_reg, .debugfs_reg_port = &debugfs_port_reg, + .snapshot_prepare = debugfs_snapshot_prepare_v3_hw, + .snapshot_restore = debugfs_snapshot_restore_v3_hw, }; static struct Scsi_Host * @@ -2405,6 +2437,7 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev) hisi_hba = shost_priv(shost); INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler); + INIT_WORK(&hisi_hba->debugfs_work, hisi_sas_debugfs_work_handler); hisi_hba->hw = &hisi_sas_v3_hw; hisi_hba->pci_dev = pdev; hisi_hba->dev = dev; -- cgit v1.2.3 From caefac1996764d19e4fa39d8d33651da257dcab2 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 19 Dec 2018 23:56:42 +0800 Subject: scsi: hisi_sas: Debugfs global register create file and add file operations This patch create debugfs file for global register and add file operations. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 8 ++++ drivers/scsi/hisi_sas/hisi_sas_main.c | 64 +++++++++++++++++++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 69 ++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 3b5fd6d638f0..6a1a5adc0878 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -221,7 +221,15 @@ struct hisi_sas_slot { u16 idx; }; +#define HISI_SAS_DEBUGFS_REG(x) {#x, x} + +struct hisi_sas_debugfs_reg_lu { + char *name; + int off; +}; + struct hisi_sas_debugfs_reg { + const struct hisi_sas_debugfs_reg_lu *lu; int count; int base_off; union { diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 742f71a8412a..fd85934d241f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2544,6 +2544,66 @@ static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) } } +const char * +hisi_sas_debugfs_to_reg_name(int off, int base_off, + const struct hisi_sas_debugfs_reg_lu *lu) +{ + for (; lu->name; lu++) { + if (off == lu->off - base_off) + return lu->name; + } + + return NULL; +} + +static void hisi_sas_debugfs_print_reg(u32 *regs_val, const void *ptr, + struct seq_file *s) +{ + const struct hisi_sas_debugfs_reg *reg = ptr; + int i; + + for (i = 0; i < reg->count; i++) { + int off = i * 4; + const char *name; + + name = hisi_sas_debugfs_to_reg_name(off, reg->base_off, + reg->lu); + + if (name) + seq_printf(s, "0x%08x 0x%08x %s\n", off, + le32_to_cpu(regs_val[i]), name); + else + seq_printf(s, "0x%08x 0x%08x\n", off, + le32_to_cpu(regs_val[i])); + } +} + +static int hisi_sas_debugfs_global_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + const struct hisi_sas_hw *hw = hisi_hba->hw; + const struct hisi_sas_debugfs_reg *reg_global = hw->debugfs_reg_global; + + hisi_sas_debugfs_print_reg((u32 *)hisi_hba->debugfs_global_reg, + reg_global, s); + + return 0; +} + +static int hisi_sas_debugfs_global_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_global_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_global_fops = { + .open = hisi_sas_debugfs_global_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) { struct dentry *dump_dentry; @@ -2554,6 +2614,10 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) goto fail; hisi_hba->debugfs_dump_dentry = dump_dentry; + + if (!debugfs_create_file("global", 0400, dump_dentry, hisi_hba, + &hisi_sas_debugfs_global_fops)) + goto fail; return; fail: debugfs_remove_recursive(hisi_hba->debugfs_dir); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 5727c265abc7..4265454ca805 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2342,7 +2342,76 @@ static const struct hisi_sas_debugfs_reg debugfs_port_reg = { .read_port_reg = hisi_sas_phy_read32, }; +static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = { + HISI_SAS_DEBUGFS_REG(DLVRY_QUEUE_ENABLE), + HISI_SAS_DEBUGFS_REG(PHY_CONTEXT), + HISI_SAS_DEBUGFS_REG(PHY_STATE), + HISI_SAS_DEBUGFS_REG(PHY_PORT_NUM_MA), + HISI_SAS_DEBUGFS_REG(PHY_CONN_RATE), + HISI_SAS_DEBUGFS_REG(ITCT_CLR), + HISI_SAS_DEBUGFS_REG(IO_SATA_BROKEN_MSG_ADDR_LO), + HISI_SAS_DEBUGFS_REG(IO_SATA_BROKEN_MSG_ADDR_HI), + HISI_SAS_DEBUGFS_REG(SATA_INITI_D2H_STORE_ADDR_LO), + HISI_SAS_DEBUGFS_REG(SATA_INITI_D2H_STORE_ADDR_HI), + HISI_SAS_DEBUGFS_REG(CFG_MAX_TAG), + HISI_SAS_DEBUGFS_REG(HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL), + HISI_SAS_DEBUGFS_REG(HGC_SAS_TXFAIL_RETRY_CTRL), + HISI_SAS_DEBUGFS_REG(HGC_GET_ITV_TIME), + HISI_SAS_DEBUGFS_REG(DEVICE_MSG_WORK_MODE), + HISI_SAS_DEBUGFS_REG(OPENA_WT_CONTI_TIME), + HISI_SAS_DEBUGFS_REG(I_T_NEXUS_LOSS_TIME), + HISI_SAS_DEBUGFS_REG(MAX_CON_TIME_LIMIT_TIME), + HISI_SAS_DEBUGFS_REG(BUS_INACTIVE_LIMIT_TIME), + HISI_SAS_DEBUGFS_REG(REJECT_TO_OPEN_LIMIT_TIME), + HISI_SAS_DEBUGFS_REG(CQ_INT_CONVERGE_EN), + HISI_SAS_DEBUGFS_REG(CFG_AGING_TIME), + HISI_SAS_DEBUGFS_REG(HGC_DFX_CFG2), + HISI_SAS_DEBUGFS_REG(CFG_ABT_SET_QUERY_IPTT), + HISI_SAS_DEBUGFS_REG(CFG_ABT_SET_IPTT_DONE), + HISI_SAS_DEBUGFS_REG(HGC_IOMB_PROC1_STATUS), + HISI_SAS_DEBUGFS_REG(CHNL_INT_STATUS), + HISI_SAS_DEBUGFS_REG(HGC_AXI_FIFO_ERR_INFO), + HISI_SAS_DEBUGFS_REG(INT_COAL_EN), + HISI_SAS_DEBUGFS_REG(OQ_INT_COAL_TIME), + HISI_SAS_DEBUGFS_REG(OQ_INT_COAL_CNT), + HISI_SAS_DEBUGFS_REG(ENT_INT_COAL_TIME), + HISI_SAS_DEBUGFS_REG(ENT_INT_COAL_CNT), + HISI_SAS_DEBUGFS_REG(OQ_INT_SRC), + HISI_SAS_DEBUGFS_REG(OQ_INT_SRC_MSK), + HISI_SAS_DEBUGFS_REG(ENT_INT_SRC1), + HISI_SAS_DEBUGFS_REG(ENT_INT_SRC2), + HISI_SAS_DEBUGFS_REG(ENT_INT_SRC3), + HISI_SAS_DEBUGFS_REG(ENT_INT_SRC_MSK1), + HISI_SAS_DEBUGFS_REG(ENT_INT_SRC_MSK2), + HISI_SAS_DEBUGFS_REG(ENT_INT_SRC_MSK3), + HISI_SAS_DEBUGFS_REG(CHNL_PHYUPDOWN_INT_MSK), + HISI_SAS_DEBUGFS_REG(CHNL_ENT_INT_MSK), + HISI_SAS_DEBUGFS_REG(HGC_COM_INT_MSK), + HISI_SAS_DEBUGFS_REG(SAS_ECC_INTR), + HISI_SAS_DEBUGFS_REG(SAS_ECC_INTR_MSK), + HISI_SAS_DEBUGFS_REG(HGC_ERR_STAT_EN), + HISI_SAS_DEBUGFS_REG(CQE_SEND_CNT), + HISI_SAS_DEBUGFS_REG(DLVRY_Q_0_DEPTH), + HISI_SAS_DEBUGFS_REG(DLVRY_Q_0_WR_PTR), + HISI_SAS_DEBUGFS_REG(DLVRY_Q_0_RD_PTR), + HISI_SAS_DEBUGFS_REG(HYPER_STREAM_ID_EN_CFG), + HISI_SAS_DEBUGFS_REG(OQ0_INT_SRC_MSK), + HISI_SAS_DEBUGFS_REG(COMPL_Q_0_DEPTH), + HISI_SAS_DEBUGFS_REG(COMPL_Q_0_WR_PTR), + HISI_SAS_DEBUGFS_REG(COMPL_Q_0_RD_PTR), + HISI_SAS_DEBUGFS_REG(AWQOS_AWCACHE_CFG), + HISI_SAS_DEBUGFS_REG(ARQOS_ARCACHE_CFG), + HISI_SAS_DEBUGFS_REG(HILINK_ERR_DFX), + HISI_SAS_DEBUGFS_REG(SAS_GPIO_CFG_0), + HISI_SAS_DEBUGFS_REG(SAS_GPIO_CFG_1), + HISI_SAS_DEBUGFS_REG(SAS_GPIO_TX_0_1), + HISI_SAS_DEBUGFS_REG(SAS_CFG_DRIVE_VLD), + {} +}; + static const struct hisi_sas_debugfs_reg debugfs_global_reg = { + .lu = debugfs_global_reg_lu, + .count = 0x800, .read_global_reg = hisi_sas_read32, }; -- cgit v1.2.3 From 61a6ebf3f584288e68254ccaddc536fcc602e5ae Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 19 Dec 2018 23:56:43 +0800 Subject: scsi: hisi_sas: Add debugfs for port registers This patch create debugfs file for port register and add file operations. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 43 ++++++++++++++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 55 ++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index fd85934d241f..fbd9b4aab628 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2604,9 +2604,38 @@ static const struct file_operations hisi_sas_debugfs_global_fops = { .owner = THIS_MODULE, }; +static int hisi_sas_debugfs_port_show(struct seq_file *s, void *p) +{ + struct hisi_sas_phy *phy = s->private; + struct hisi_hba *hisi_hba = phy->hisi_hba; + const struct hisi_sas_hw *hw = hisi_hba->hw; + const struct hisi_sas_debugfs_reg *reg_port = hw->debugfs_reg_port; + u32 *databuf = hisi_hba->debugfs_port_reg[phy->sas_phy.id]; + + hisi_sas_debugfs_print_reg(databuf, reg_port, s); + + return 0; +} + +static int hisi_sas_debugfs_port_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_port_show, inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_port_fops = { + .open = hisi_sas_debugfs_port_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) { struct dentry *dump_dentry; + struct dentry *dentry; + char name[256]; + int p; /* Create dump dir inside device dir */ dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); @@ -2618,6 +2647,20 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) if (!debugfs_create_file("global", 0400, dump_dentry, hisi_hba, &hisi_sas_debugfs_global_fops)) goto fail; + + /* Create port dir and files */ + dentry = debugfs_create_dir("port", dump_dentry); + if (!dentry) + goto fail; + + for (p = 0; p < hisi_hba->n_phy; p++) { + snprintf(name, 256, "%d", p); + if (!debugfs_create_file(name, 0400, dentry, + &hisi_hba->phy[p], + &hisi_sas_debugfs_port_fops)) + goto fail; + } + return; fail: debugfs_remove_recursive(hisi_hba->debugfs_dir); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 4265454ca805..b780b5269f0f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -186,6 +186,7 @@ #define CHL_INT0_MSK (PORT_BASE + 0x1c0) #define CHL_INT1_MSK (PORT_BASE + 0x1c4) #define CHL_INT2_MSK (PORT_BASE + 0x1c8) +#define SAS_EC_INT_COAL_TIME (PORT_BASE + 0x1cc) #define CHL_INT_COAL_EN (PORT_BASE + 0x1d0) #define SAS_RX_TRAIN_TIMER (PORT_BASE + 0x2a4) #define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0) @@ -205,6 +206,7 @@ #define ERR_CNT_DWS_LOST (PORT_BASE + 0x380) #define ERR_CNT_RESET_PROB (PORT_BASE + 0x384) #define ERR_CNT_INVLD_DW (PORT_BASE + 0x390) +#define ERR_CNT_CODE_ERR (PORT_BASE + 0x394) #define ERR_CNT_DISP_ERR (PORT_BASE + 0x398) #define DEFAULT_ITCT_HW 2048 /* reset value, not reprogrammed */ @@ -2337,7 +2339,60 @@ static struct device_attribute *host_attrs_v3_hw[] = { NULL }; +static const struct hisi_sas_debugfs_reg_lu debugfs_port_reg_lu[] = { + HISI_SAS_DEBUGFS_REG(PHY_CFG), + HISI_SAS_DEBUGFS_REG(HARD_PHY_LINKRATE), + HISI_SAS_DEBUGFS_REG(PROG_PHY_LINK_RATE), + HISI_SAS_DEBUGFS_REG(PHY_CTRL), + HISI_SAS_DEBUGFS_REG(SL_CFG), + HISI_SAS_DEBUGFS_REG(AIP_LIMIT), + HISI_SAS_DEBUGFS_REG(SL_CONTROL), + HISI_SAS_DEBUGFS_REG(RX_PRIMS_STATUS), + HISI_SAS_DEBUGFS_REG(TX_ID_DWORD0), + HISI_SAS_DEBUGFS_REG(TX_ID_DWORD1), + HISI_SAS_DEBUGFS_REG(TX_ID_DWORD2), + HISI_SAS_DEBUGFS_REG(TX_ID_DWORD3), + HISI_SAS_DEBUGFS_REG(TX_ID_DWORD4), + HISI_SAS_DEBUGFS_REG(TX_ID_DWORD5), + HISI_SAS_DEBUGFS_REG(TX_ID_DWORD6), + HISI_SAS_DEBUGFS_REG(TXID_AUTO), + HISI_SAS_DEBUGFS_REG(RX_IDAF_DWORD0), + HISI_SAS_DEBUGFS_REG(RXOP_CHECK_CFG_H), + HISI_SAS_DEBUGFS_REG(STP_LINK_TIMER), + HISI_SAS_DEBUGFS_REG(STP_LINK_TIMEOUT_STATE), + HISI_SAS_DEBUGFS_REG(CON_CFG_DRIVER), + HISI_SAS_DEBUGFS_REG(SAS_SSP_CON_TIMER_CFG), + HISI_SAS_DEBUGFS_REG(SAS_SMP_CON_TIMER_CFG), + HISI_SAS_DEBUGFS_REG(SAS_STP_CON_TIMER_CFG), + HISI_SAS_DEBUGFS_REG(CHL_INT0), + HISI_SAS_DEBUGFS_REG(CHL_INT1), + HISI_SAS_DEBUGFS_REG(CHL_INT2), + HISI_SAS_DEBUGFS_REG(CHL_INT0_MSK), + HISI_SAS_DEBUGFS_REG(CHL_INT1_MSK), + HISI_SAS_DEBUGFS_REG(CHL_INT2_MSK), + HISI_SAS_DEBUGFS_REG(SAS_EC_INT_COAL_TIME), + HISI_SAS_DEBUGFS_REG(CHL_INT_COAL_EN), + HISI_SAS_DEBUGFS_REG(SAS_RX_TRAIN_TIMER), + HISI_SAS_DEBUGFS_REG(PHY_CTRL_RDY_MSK), + HISI_SAS_DEBUGFS_REG(PHYCTRL_NOT_RDY_MSK), + HISI_SAS_DEBUGFS_REG(PHYCTRL_DWS_RESET_MSK), + HISI_SAS_DEBUGFS_REG(PHYCTRL_PHY_ENA_MSK), + HISI_SAS_DEBUGFS_REG(SL_RX_BCAST_CHK_MSK), + HISI_SAS_DEBUGFS_REG(PHYCTRL_OOB_RESTART_MSK), + HISI_SAS_DEBUGFS_REG(DMA_TX_STATUS), + HISI_SAS_DEBUGFS_REG(DMA_RX_STATUS), + HISI_SAS_DEBUGFS_REG(COARSETUNE_TIME), + HISI_SAS_DEBUGFS_REG(ERR_CNT_DWS_LOST), + HISI_SAS_DEBUGFS_REG(ERR_CNT_RESET_PROB), + HISI_SAS_DEBUGFS_REG(ERR_CNT_INVLD_DW), + HISI_SAS_DEBUGFS_REG(ERR_CNT_CODE_ERR), + HISI_SAS_DEBUGFS_REG(ERR_CNT_DISP_ERR), + {} +}; + static const struct hisi_sas_debugfs_reg debugfs_port_reg = { + .lu = debugfs_port_reg_lu, + .count = 0x100, .base_off = PORT_BASE, .read_port_reg = hisi_sas_phy_read32, }; -- cgit v1.2.3 From 971afae7cf4f784c37ea89459c1b3627bcf601ff Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 19 Dec 2018 23:56:44 +0800 Subject: scsi: hisi_sas: Add debugfs CQ file and add file operations This patch create debugfs file for CQ and add file operations. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index fbd9b4aab628..ce0a9dcc355b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2630,12 +2630,68 @@ static const struct file_operations hisi_sas_debugfs_port_fops = { .owner = THIS_MODULE, }; +static int hisi_sas_show_row_32(struct seq_file *s, int index, + int sz, u32 *ptr) +{ + int i; + + /* completion header size not fixed per HW version */ + seq_printf(s, "index %04d:\n\t", index); + for (i = 1; i <= sz / 4; i++, ptr++) { + if (!(i % 4)) + seq_puts(s, "\n\t"); + } + seq_puts(s, "\n"); + + return 0; +} + +static int hisi_sas_cq_show_slot(struct seq_file *s, int slot, void *cq_ptr) +{ + struct hisi_sas_cq *cq = cq_ptr; + struct hisi_hba *hisi_hba = cq->hisi_hba; + void *complete_queue = hisi_hba->debugfs_complete_hdr[cq->id]; + void *complete_hdr = complete_queue + + (hisi_hba->hw->complete_hdr_size * slot); + + return hisi_sas_show_row_32(s, slot, + hisi_hba->hw->complete_hdr_size, + complete_hdr); +} + +static int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p) +{ + struct hisi_sas_cq *cq = s->private; + int slot, ret; + + for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { + ret = hisi_sas_cq_show_slot(s, slot, cq); + if (ret) + return ret; + } + return 0; +} + +static int hisi_sas_debugfs_cq_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_cq_show, inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_cq_fops = { + .open = hisi_sas_debugfs_cq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) { struct dentry *dump_dentry; struct dentry *dentry; char name[256]; int p; + int c; /* Create dump dir inside device dir */ dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); @@ -2661,6 +2717,20 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) goto fail; } + /* Create CQ dir and files */ + dentry = debugfs_create_dir("cq", dump_dentry); + if (!dentry) + goto fail; + + for (c = 0; c < hisi_hba->queue_count; c++) { + snprintf(name, 256, "%d", c); + + if (!debugfs_create_file(name, 0400, dentry, + &hisi_hba->cq[c], + &hisi_sas_debugfs_cq_fops)) + goto fail; + } + return; fail: debugfs_remove_recursive(hisi_hba->debugfs_dir); -- cgit v1.2.3 From 148e379f60c5ce0a9741ccdada46ba91579a9df7 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 19 Dec 2018 23:56:45 +0800 Subject: scsi: hisi_sas: Add debugfs DQ file and add file operations This patch create debugfs file for DQ and add file operations Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index ce0a9dcc355b..45a0be2411a5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2685,6 +2685,43 @@ static const struct file_operations hisi_sas_debugfs_cq_fops = { .owner = THIS_MODULE, }; +static int hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr) +{ + struct hisi_sas_dq *dq = dq_ptr; + struct hisi_hba *hisi_hba = dq->hisi_hba; + void *cmd_queue = hisi_hba->debugfs_cmd_hdr[dq->id]; + void *cmd_hdr = cmd_queue + + hisi_hba->hw->complete_hdr_size * slot; + + return hisi_sas_show_row_32(s, slot, sizeof(struct hisi_sas_cmd_hdr), + cmd_hdr); +} + +static int hisi_sas_debugfs_dq_show(struct seq_file *s, void *p) +{ + int slot, ret; + + for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { + ret = hisi_sas_dq_show_slot(s, slot, s->private); + if (ret) + return ret; + } + return 0; +} + +static int hisi_sas_debugfs_dq_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_dq_show, inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_dq_fops = { + .open = hisi_sas_debugfs_dq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) { struct dentry *dump_dentry; @@ -2692,6 +2729,7 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) char name[256]; int p; int c; + int d; /* Create dump dir inside device dir */ dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); @@ -2731,6 +2769,20 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) goto fail; } + /* Create DQ dir and files */ + dentry = debugfs_create_dir("dq", dump_dentry); + if (!dentry) + goto fail; + + for (d = 0; d < hisi_hba->queue_count; d++) { + snprintf(name, 256, "%d", d); + + if (!debugfs_create_file(name, 0400, dentry, + &hisi_hba->dq[d], + &hisi_sas_debugfs_dq_fops)) + goto fail; + } + return; fail: debugfs_remove_recursive(hisi_hba->debugfs_dir); -- cgit v1.2.3 From 1afb4b8524797f95b15480a6654780571cde4e56 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 19 Dec 2018 23:56:46 +0800 Subject: scsi: hisi_sas: Add debugfs IOST file and add file operations This patch create debugfs file for IOST and add file operations. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 45a0be2411a5..3d24366ceeef 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2630,6 +2630,24 @@ static const struct file_operations hisi_sas_debugfs_port_fops = { .owner = THIS_MODULE, }; +static int hisi_sas_show_row_64(struct seq_file *s, int index, + int sz, u64 *ptr) +{ + int i; + + /* completion header size not fixed per HW version */ + seq_printf(s, "index %04d:\n\t", index); + for (i = 1; i <= sz / 8; i++, ptr++) { + seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr)); + if (!(i % 2)) + seq_puts(s, "\n\t"); + } + + seq_puts(s, "\n"); + + return 0; +} + static int hisi_sas_show_row_32(struct seq_file *s, int index, int sz, u32 *ptr) { @@ -2722,6 +2740,35 @@ static const struct file_operations hisi_sas_debugfs_dq_fops = { .owner = THIS_MODULE, }; +static int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + struct hisi_sas_iost *debugfs_iost = hisi_hba->debugfs_iost; + int i, ret, max_command_entries = hisi_hba->hw->max_command_entries; + + for (i = 0; i < max_command_entries; i++, debugfs_iost++) { + ret = hisi_sas_show_row_64(s, i, sizeof(*debugfs_iost), + (u64 *)debugfs_iost); + if (ret) + return ret; + } + + return 0; +} + +static int hisi_sas_debugfs_iost_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_iost_show, inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_iost_fops = { + .open = hisi_sas_debugfs_iost_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) { struct dentry *dump_dentry; @@ -2783,6 +2830,10 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) goto fail; } + if (!debugfs_create_file("iost", 0400, dump_dentry, hisi_hba, + &hisi_sas_debugfs_iost_fops)) + goto fail; + return; fail: debugfs_remove_recursive(hisi_hba->debugfs_dir); -- cgit v1.2.3 From 082c2cd2030e5e9322c835f577fdc9acff41ee5b Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 8 Jan 2019 23:14:52 +0800 Subject: scsi: sd: Make protection lookup tables static and relocate functions Currently the protection lookup tables in sd_prot_flag_mask() and sd_prot_op() are declared as non-static. As such, they will be rebuilt for each respective function call. Optimise by making them static. This saves ~100B object code for sd.c: Before: text data bss dec hex filename 25403 1024 16 26443 674b drivers/scsi/sd.o After: text data bss dec hex filename 25299 1024 16 26339 66e3 drivers/scsi/sd.o In addition, since those same functions are declared in sd.h, but each are only referenced in sd.c, relocate them to that same c file. The inline specifier is dropped also, since gcc should be able to make the decision to inline. Signed-off-by: John Garry Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/sd.h | 62 ------------------------------------------------------- 2 files changed, 62 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a1a44f52e0e8..c6ca3d915925 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -659,6 +659,68 @@ static int sd_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, } #endif /* CONFIG_BLK_SED_OPAL */ +/* + * Look up the DIX operation based on whether the command is read or + * write and whether dix and dif are enabled. + */ +static unsigned int sd_prot_op(bool write, bool dix, bool dif) +{ + /* Lookup table: bit 2 (write), bit 1 (dix), bit 0 (dif) */ + static const unsigned int ops[] = { /* wrt dix dif */ + SCSI_PROT_NORMAL, /* 0 0 0 */ + SCSI_PROT_READ_STRIP, /* 0 0 1 */ + SCSI_PROT_READ_INSERT, /* 0 1 0 */ + SCSI_PROT_READ_PASS, /* 0 1 1 */ + SCSI_PROT_NORMAL, /* 1 0 0 */ + SCSI_PROT_WRITE_INSERT, /* 1 0 1 */ + SCSI_PROT_WRITE_STRIP, /* 1 1 0 */ + SCSI_PROT_WRITE_PASS, /* 1 1 1 */ + }; + + return ops[write << 2 | dix << 1 | dif]; +} + +/* + * Returns a mask of the protection flags that are valid for a given DIX + * operation. + */ +static unsigned int sd_prot_flag_mask(unsigned int prot_op) +{ + static const unsigned int flag_mask[] = { + [SCSI_PROT_NORMAL] = 0, + + [SCSI_PROT_READ_STRIP] = SCSI_PROT_TRANSFER_PI | + SCSI_PROT_GUARD_CHECK | + SCSI_PROT_REF_CHECK | + SCSI_PROT_REF_INCREMENT, + + [SCSI_PROT_READ_INSERT] = SCSI_PROT_REF_INCREMENT | + SCSI_PROT_IP_CHECKSUM, + + [SCSI_PROT_READ_PASS] = SCSI_PROT_TRANSFER_PI | + SCSI_PROT_GUARD_CHECK | + SCSI_PROT_REF_CHECK | + SCSI_PROT_REF_INCREMENT | + SCSI_PROT_IP_CHECKSUM, + + [SCSI_PROT_WRITE_INSERT] = SCSI_PROT_TRANSFER_PI | + SCSI_PROT_REF_INCREMENT, + + [SCSI_PROT_WRITE_STRIP] = SCSI_PROT_GUARD_CHECK | + SCSI_PROT_REF_CHECK | + SCSI_PROT_REF_INCREMENT | + SCSI_PROT_IP_CHECKSUM, + + [SCSI_PROT_WRITE_PASS] = SCSI_PROT_TRANSFER_PI | + SCSI_PROT_GUARD_CHECK | + SCSI_PROT_REF_CHECK | + SCSI_PROT_REF_INCREMENT | + SCSI_PROT_IP_CHECKSUM, + }; + + return flag_mask[prot_op]; +} + static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd, unsigned int dix, unsigned int dif) { diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 7f43e6839bce..1080c85d97f8 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -188,68 +188,6 @@ static inline sector_t sectors_to_logical(struct scsi_device *sdev, sector_t sec return sector >> (ilog2(sdev->sector_size) - 9); } -/* - * Look up the DIX operation based on whether the command is read or - * write and whether dix and dif are enabled. - */ -static inline unsigned int sd_prot_op(bool write, bool dix, bool dif) -{ - /* Lookup table: bit 2 (write), bit 1 (dix), bit 0 (dif) */ - const unsigned int ops[] = { /* wrt dix dif */ - SCSI_PROT_NORMAL, /* 0 0 0 */ - SCSI_PROT_READ_STRIP, /* 0 0 1 */ - SCSI_PROT_READ_INSERT, /* 0 1 0 */ - SCSI_PROT_READ_PASS, /* 0 1 1 */ - SCSI_PROT_NORMAL, /* 1 0 0 */ - SCSI_PROT_WRITE_INSERT, /* 1 0 1 */ - SCSI_PROT_WRITE_STRIP, /* 1 1 0 */ - SCSI_PROT_WRITE_PASS, /* 1 1 1 */ - }; - - return ops[write << 2 | dix << 1 | dif]; -} - -/* - * Returns a mask of the protection flags that are valid for a given DIX - * operation. - */ -static inline unsigned int sd_prot_flag_mask(unsigned int prot_op) -{ - const unsigned int flag_mask[] = { - [SCSI_PROT_NORMAL] = 0, - - [SCSI_PROT_READ_STRIP] = SCSI_PROT_TRANSFER_PI | - SCSI_PROT_GUARD_CHECK | - SCSI_PROT_REF_CHECK | - SCSI_PROT_REF_INCREMENT, - - [SCSI_PROT_READ_INSERT] = SCSI_PROT_REF_INCREMENT | - SCSI_PROT_IP_CHECKSUM, - - [SCSI_PROT_READ_PASS] = SCSI_PROT_TRANSFER_PI | - SCSI_PROT_GUARD_CHECK | - SCSI_PROT_REF_CHECK | - SCSI_PROT_REF_INCREMENT | - SCSI_PROT_IP_CHECKSUM, - - [SCSI_PROT_WRITE_INSERT] = SCSI_PROT_TRANSFER_PI | - SCSI_PROT_REF_INCREMENT, - - [SCSI_PROT_WRITE_STRIP] = SCSI_PROT_GUARD_CHECK | - SCSI_PROT_REF_CHECK | - SCSI_PROT_REF_INCREMENT | - SCSI_PROT_IP_CHECKSUM, - - [SCSI_PROT_WRITE_PASS] = SCSI_PROT_TRANSFER_PI | - SCSI_PROT_GUARD_CHECK | - SCSI_PROT_REF_CHECK | - SCSI_PROT_REF_INCREMENT | - SCSI_PROT_IP_CHECKSUM, - }; - - return flag_mask[prot_op]; -} - #ifdef CONFIG_BLK_DEV_INTEGRITY extern void sd_dif_config_host(struct scsi_disk *); -- cgit v1.2.3 From 7b8f32eee779b6ab93f65aaddbfce6a553b18a77 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 4 Jan 2019 17:02:24 +0000 Subject: scsi: bnx2i: fix indentation issue, remove a tab The return statement is indented incorrectly, fix this by removing a single tab. Signed-off-by: Colin Ian King Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 69c75426c5eb..c5fa5f3b00e9 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -577,7 +577,7 @@ static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba) hba->dummy_buffer, hba->dummy_buf_dma); hba->dummy_buffer = NULL; } - return; + return; } /** -- cgit v1.2.3 From a20ca6744ba7e683a772bb5f1715e4662342be58 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Jan 2019 12:43:56 -0800 Subject: Build etnaviv on non-ARM architectures I wanted to test-compile etnaviv on x86 after making a tree-wide change to it. Unfortunately, Kconfig has a bad dependency, so I couldn't. Signed-off-by: Matthew Wilcox Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig index 041a77e400d4..342591a1084e 100644 --- a/drivers/gpu/drm/etnaviv/Kconfig +++ b/drivers/gpu/drm/etnaviv/Kconfig @@ -2,7 +2,7 @@ config DRM_ETNAVIV tristate "ETNAVIV (DRM support for Vivante GPU IP cores)" depends on DRM - depends on ARCH_MXC || ARCH_DOVE || (ARM && COMPILE_TEST) + depends on ARCH_MXC || ARCH_DOVE || ARM || COMPILE_TEST depends on MMU select SHMEM select SYNC_FILE -- cgit v1.2.3 From f3186dd876697e696d07136623d5cf0a6fb0bc0f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 7 Jan 2019 16:51:50 +0100 Subject: spi: Optionally use GPIO descriptors for CS GPIOs This augments the SPI core to optionally use GPIO descriptors for chip select on a per-master-driver opt-in basis. Drivers using this will rely on the SPI core to look up GPIO descriptors associated with the device, such as when using device tree or board files with GPIO descriptor tables. When getting descriptors from the device tree, this will in turn activate the code in gpiolib that was added in commit 6953c57ab172 ("gpio: of: Handle SPI chipselect legacy bindings") which means that these descriptors are aware of the active low semantics that is the default for SPI CS GPIO lines and we can assume that all of these are "active high" and thus assign SPI_CS_HIGH to all CS lines on the DT path. The previously used gpio_set_value() would call down into gpiod_set_raw_value() and ignore the polarity inversion semantics. It seems like many drivers go to great lengths to set up the CS GPIO line as non-asserted, respecting SPI_CS_HIGH. We pull this out of the SPI drivers and into the core, and by simply requesting the line as GPIOD_OUT_LOW when retrieveing it from the device and relying on the gpiolib to handle any inversion semantics. This way a lot of code can be simplified and removed in each converted driver. The end goal after dealing with each driver in turn, is to delete the non-descriptor path (of_spi_register_master() for example) and let the core deal with only descriptors. The different SPI drivers have complex interactions with the core so we cannot simply change them all over, we need to use a stepwise, bisectable approach so that each driver can be converted and fixed in isolation. This patch has the intended side effect of adding support for ACPI GPIOs as it starts relying on gpiod_get_*() to get the GPIO handle associated with the device. Cc: Linuxarm Acked-by: Jonathan Cameron Tested-by: Fangjian (Turing) Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9a7def7c3237..13f447a67d67 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -578,7 +579,10 @@ int spi_add_device(struct spi_device *spi) goto done; } - if (ctlr->cs_gpios) + /* Descriptors take precedence */ + if (ctlr->cs_gpiods) + spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select]; + else if (ctlr->cs_gpios) spi->cs_gpio = ctlr->cs_gpios[spi->chip_select]; /* Drivers may modify this initial i/o setup, but will @@ -772,10 +776,20 @@ static void spi_set_cs(struct spi_device *spi, bool enable) if (spi->mode & SPI_CS_HIGH) enable = !enable; - if (gpio_is_valid(spi->cs_gpio)) { - /* Honour the SPI_NO_CS flag */ - if (!(spi->mode & SPI_NO_CS)) - gpio_set_value(spi->cs_gpio, !enable); + if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio)) { + /* + * Honour the SPI_NO_CS flag and invert the enable line, as + * active low is default for SPI. Execution paths that handle + * polarity inversion in gpiolib (such as device tree) will + * enforce active high using the SPI_CS_HIGH resulting in a + * double inversion through the code above. + */ + if (!(spi->mode & SPI_NO_CS)) { + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, !enable); + else + gpio_set_value(spi->cs_gpio, !enable); + } /* Some SPI masters need both GPIO CS & slave_select */ if ((spi->controller->flags & SPI_MASTER_GPIO_SS) && spi->controller->set_cs) @@ -1615,13 +1629,21 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, spi->mode |= SPI_CPHA; if (of_property_read_bool(nc, "spi-cpol")) spi->mode |= SPI_CPOL; - if (of_property_read_bool(nc, "spi-cs-high")) - spi->mode |= SPI_CS_HIGH; if (of_property_read_bool(nc, "spi-3wire")) spi->mode |= SPI_3WIRE; if (of_property_read_bool(nc, "spi-lsb-first")) spi->mode |= SPI_LSB_FIRST; + /* + * For descriptors associated with the device, polarity inversion is + * handled in the gpiolib, so all chip selects are "active high" in + * the logical sense, the gpiolib will invert the line if need be. + */ + if (ctlr->use_gpio_descriptors) + spi->mode |= SPI_CS_HIGH; + else if (of_property_read_bool(nc, "spi-cs-high")) + spi->mode |= SPI_CS_HIGH; + /* Device DUAL/QUAD mode */ if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) { switch (value) { @@ -2137,6 +2159,60 @@ static int of_spi_register_master(struct spi_controller *ctlr) } #endif +/** + * spi_get_gpio_descs() - grab chip select GPIOs for the master + * @ctlr: The SPI master to grab GPIO descriptors for + */ +static int spi_get_gpio_descs(struct spi_controller *ctlr) +{ + int nb, i; + struct gpio_desc **cs; + struct device *dev = &ctlr->dev; + + nb = gpiod_count(dev, "cs"); + ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect); + + /* No GPIOs at all is fine, else return the error */ + if (nb == 0 || nb == -ENOENT) + return 0; + else if (nb < 0) + return nb; + + cs = devm_kcalloc(dev, ctlr->num_chipselect, sizeof(*cs), + GFP_KERNEL); + if (!cs) + return -ENOMEM; + ctlr->cs_gpiods = cs; + + for (i = 0; i < nb; i++) { + /* + * Most chipselects are active low, the inverted + * semantics are handled by special quirks in gpiolib, + * so initializing them GPIOD_OUT_LOW here means + * "unasserted", in most cases this will drive the physical + * line high. + */ + cs[i] = devm_gpiod_get_index_optional(dev, "cs", i, + GPIOD_OUT_LOW); + + if (cs[i]) { + /* + * If we find a CS GPIO, name it after the device and + * chip select line. + */ + char *gpioname; + + gpioname = devm_kasprintf(dev, GFP_KERNEL, "%s CS%d", + dev_name(dev), i); + if (!gpioname) + return -ENOMEM; + gpiod_set_consumer_name(cs[i], gpioname); + } + } + + return 0; +} + static int spi_controller_check_ops(struct spi_controller *ctlr) { /* @@ -2199,9 +2275,16 @@ int spi_register_controller(struct spi_controller *ctlr) return status; if (!spi_controller_is_slave(ctlr)) { - status = of_spi_register_master(ctlr); - if (status) - return status; + if (ctlr->use_gpio_descriptors) { + status = spi_get_gpio_descs(ctlr); + if (status) + return status; + } else { + /* Legacy code path for GPIOs from DT */ + status = of_spi_register_master(ctlr); + if (status) + return status; + } } /* even if it's just one always-selected device, there must @@ -2915,6 +2998,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) * cs_change is set for each transfer. */ if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) || + spi->cs_gpiod || gpio_is_valid(spi->cs_gpio))) { size_t maxsize; int ret; -- cgit v1.2.3 From 8db79547e79f6606b6d2d3b2bf6f36ec311195be Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 7 Jan 2019 16:51:51 +0100 Subject: spi: ath79: Convert to use CS GPIO descriptors This converts the ATH79 SPI master driver to use GPIO descriptors for chip select handling. The ATH79 driver was requesting the GPIO and driving it from the bitbang .chipselect callback. Do not request it anymore as the SPI core will request it, remove the line inversion semantics for the GPIO case (handled by gpiolib) and let the SPI core deal with requesting the GPIO line from the device tree node of the controller. This driver can be instantiated from a board file (no device tree) but the board files only use native CS (no GPIO lines) so we should be fine just letting the SPI core grab the GPIO from the device. The fact that the driver is actively driving the GPIO in the ath79_spi_chipselect() callback is confusing since the host does not set SPI_MASTER_GPIO_SS so this should not ever get called when using GPIO CS. I put in a comment about this. Cc: Felix Fietkau Cc: Alban Bedel Cc: Linuxarm Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 3f6b657394de..ed1068ac055f 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -78,9 +78,16 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active) ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } - if (gpio_is_valid(spi->cs_gpio)) { - /* SPI is normally active-low */ - gpio_set_value_cansleep(spi->cs_gpio, cs_high); + if (spi->cs_gpiod) { + /* + * SPI chipselect is normally active-low, but + * inversion semantics are handled by gpiolib. + * + * FIXME: is this ever used? The driver doesn't + * set SPI_MASTER_GPIO_SS so this callback should not + * get called if a CS GPIO is found by the SPI core. + */ + gpiod_set_value_cansleep(spi->cs_gpiod, is_active); } else { u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); @@ -118,21 +125,8 @@ static void ath79_spi_disable(struct ath79_spi *sp) static int ath79_spi_setup_cs(struct spi_device *spi) { struct ath79_spi *sp = ath79_spidev_to_sp(spi); - int status; - status = 0; - if (gpio_is_valid(spi->cs_gpio)) { - unsigned long flags; - - flags = GPIOF_DIR_OUT; - if (spi->mode & SPI_CS_HIGH) - flags |= GPIOF_INIT_LOW; - else - flags |= GPIOF_INIT_HIGH; - - status = gpio_request_one(spi->cs_gpio, flags, - dev_name(&spi->dev)); - } else { + if (!spi->cs_gpiod) { u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); if (spi->mode & SPI_CS_HIGH) @@ -143,13 +137,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi) ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } - return status; -} - -static void ath79_spi_cleanup_cs(struct spi_device *spi) -{ - if (gpio_is_valid(spi->cs_gpio)) - gpio_free(spi->cs_gpio); + return 0; } static int ath79_spi_setup(struct spi_device *spi) @@ -163,15 +151,12 @@ static int ath79_spi_setup(struct spi_device *spi) } status = spi_bitbang_setup(spi); - if (status && !spi->controller_state) - ath79_spi_cleanup_cs(spi); return status; } static void ath79_spi_cleanup(struct spi_device *spi) { - ath79_spi_cleanup_cs(spi); spi_bitbang_cleanup(spi); } @@ -225,6 +210,7 @@ static int ath79_spi_probe(struct platform_device *pdev) pdata = dev_get_platdata(&pdev->dev); + master->use_gpio_descriptors = true; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->setup = ath79_spi_setup; master->cleanup = ath79_spi_cleanup; -- cgit v1.2.3 From efc92fbb876014c8efa4d90f4ac4b49569f0a84e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 7 Jan 2019 16:51:52 +0100 Subject: spi: atmel: Convert to use CS GPIO descriptors This converts the Atmel SPI master driver to use GPIO descriptors for chip select handling. The Atmel driver has duplicate code to look up and initialize CS GPIOs from the device tree, so this is removed. It further has code to retrieve a CS GPIO from .controller_data but this seems to be completely unused in the kernel (legacy codepath?) so I deleted this support. It keeps track of polarity when switching the CS, but this is not needed anymore since we moved this over to the gpiolib. The local handling of the "npcs_pin" (I guess this might mean "negative polarity chip select pin") is preserved, but I strongly suspect this can be switched over to handling by the core and using the SPI_MASTER_GPIO_SS flag on the master to assure that the additional CS handling in the driver is also done. Cc: Eugen Hristev Cc: Nicolas Ferre Cc: Radu Pirea Cc: Linuxarm Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 93 ++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 74fddcd3282b..f53f0c5e63da 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -23,8 +23,7 @@ #include #include -#include -#include +#include #include #include @@ -312,7 +311,7 @@ struct atmel_spi { /* Controller-specific per-slave state */ struct atmel_spi_device { - unsigned int npcs_pin; + struct gpio_desc *npcs_pin; u32 csr; }; @@ -355,7 +354,6 @@ static bool atmel_spi_is_v2(struct atmel_spi *as) static void cs_activate(struct atmel_spi *as, struct spi_device *spi) { struct atmel_spi_device *asd = spi->controller_state; - unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; if (atmel_spi_is_v2(as)) { @@ -379,7 +377,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) mr = spi_readl(as, MR); if (as->use_cs_gpios) - gpio_set_value(asd->npcs_pin, active); + gpiod_set_value(asd->npcs_pin, 1); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; @@ -396,19 +394,16 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); if (as->use_cs_gpios && spi->chip_select != 0) - gpio_set_value(asd->npcs_pin, active); + gpiod_set_value(asd->npcs_pin, 1); spi_writel(as, MR, mr); } - dev_dbg(&spi->dev, "activate %u%s, mr %08x\n", - asd->npcs_pin, active ? " (high)" : "", - mr); + dev_dbg(&spi->dev, "activate NPCS, mr %08x\n", mr); } static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) { struct atmel_spi_device *asd = spi->controller_state; - unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; /* only deactivate *this* device; sometimes transfers to @@ -420,14 +415,12 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) spi_writel(as, MR, mr); } - dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n", - asd->npcs_pin, active ? " (low)" : "", - mr); + dev_dbg(&spi->dev, "DEactivate NPCS, mr %08x\n", mr); if (!as->use_cs_gpios) spi_writel(as, CR, SPI_BIT(LASTXFER)); else if (atmel_spi_is_v2(as) || spi->chip_select != 0) - gpio_set_value(asd->npcs_pin, !active); + gpiod_set_value(asd->npcs_pin, 0); } static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock) @@ -1188,7 +1181,6 @@ static int atmel_spi_setup(struct spi_device *spi) struct atmel_spi_device *asd; u32 csr; unsigned int bits = spi->bits_per_word; - unsigned int npcs_pin; as = spi_master_get_devdata(spi->master); @@ -1217,25 +1209,27 @@ static int atmel_spi_setup(struct spi_device *spi) csr |= SPI_BF(DLYBS, 0); csr |= SPI_BF(DLYBCT, 0); - /* chipselect must have been muxed as GPIO (e.g. in board setup) */ - npcs_pin = (unsigned long)spi->controller_data; - - if (!as->use_cs_gpios) - npcs_pin = spi->chip_select; - else if (gpio_is_valid(spi->cs_gpio)) - npcs_pin = spi->cs_gpio; - asd = spi->controller_state; if (!asd) { asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL); if (!asd) return -ENOMEM; - if (as->use_cs_gpios) - gpio_direction_output(npcs_pin, - !(spi->mode & SPI_CS_HIGH)); + /* + * If use_cs_gpios is true this means that we have "cs-gpios" + * defined in the device tree node so we should have + * gotten the GPIO lines from the device tree inside the + * SPI core. Warn if this is not the case but continue since + * CS GPIOs are after all optional. + */ + if (as->use_cs_gpios) { + if (!spi->cs_gpiod) { + dev_err(&spi->dev, + "host claims to use CS GPIOs but no CS found in DT by the SPI core\n"); + } + asd->npcs_pin = spi->cs_gpiod; + } - asd->npcs_pin = npcs_pin; spi->controller_state = asd; } @@ -1473,41 +1467,6 @@ static void atmel_get_caps(struct atmel_spi *as) as->caps.has_pdc_support = version < 0x212; } -/*-------------------------------------------------------------------------*/ -static int atmel_spi_gpio_cs(struct platform_device *pdev) -{ - struct spi_master *master = platform_get_drvdata(pdev); - struct atmel_spi *as = spi_master_get_devdata(master); - struct device_node *np = master->dev.of_node; - int i; - int ret = 0; - int nb = 0; - - if (!as->use_cs_gpios) - return 0; - - if (!np) - return 0; - - nb = of_gpio_named_count(np, "cs-gpios"); - for (i = 0; i < nb; i++) { - int cs_gpio = of_get_named_gpio(pdev->dev.of_node, - "cs-gpios", i); - - if (cs_gpio == -EPROBE_DEFER) - return cs_gpio; - - if (gpio_is_valid(cs_gpio)) { - ret = devm_gpio_request(&pdev->dev, cs_gpio, - dev_name(&pdev->dev)); - if (ret) - return ret; - } - } - - return 0; -} - static void atmel_spi_init(struct atmel_spi *as) { spi_writel(as, CR, SPI_BIT(SWRST)); @@ -1560,6 +1519,7 @@ static int atmel_spi_probe(struct platform_device *pdev) goto out_free; /* the spi->mode bits understood by this driver: */ + master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); master->dev.of_node = pdev->dev.of_node; @@ -1592,6 +1552,11 @@ static int atmel_spi_probe(struct platform_device *pdev) atmel_get_caps(as); + /* + * If there are chip selects in the device tree, those will be + * discovered by the SPI core when registering the SPI master + * and assigned to each SPI device. + */ as->use_cs_gpios = true; if (atmel_spi_is_v2(as) && pdev->dev.of_node && @@ -1600,10 +1565,6 @@ static int atmel_spi_probe(struct platform_device *pdev) master->num_chipselect = 4; } - ret = atmel_spi_gpio_cs(pdev); - if (ret) - goto out_unmap_regs; - as->use_dma = false; as->use_pdc = false; if (as->caps.has_dma_support) { -- cgit v1.2.3 From cfeefa79dc37d378216e2ced1600e297dd04e591 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 7 Jan 2019 16:51:53 +0100 Subject: spi: cadence: Convert to use CS GPIO descriptors This converts the Cadence SPI master driver to use GPIO descriptors for chip select handling. The Cadence driver was allocating a state container just to hold the requested GPIO line and contained lots of polarity inversion code. As this is all handled by gpiolib and a simple devm_* request in the core, and as the driver is fully device tree only, most of this code chunk goes away in favour of central handling. The setup/cleanup callbacks goes away. This driver does NOT drive the CS line by setting the value of the GPIO so it relies on the SPI core to do this, which should work just fine with the descriptors. Cc: Wei Yongjun Cc: Janek Kotas Cc: Linuxarm Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 67 ++--------------------------------------------- 1 file changed, 2 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 7c88f74f7f47..e332d173dbf9 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include @@ -128,10 +128,6 @@ struct cdns_spi { u32 is_decoded_cs; }; -struct cdns_spi_device_data { - bool gpio_requested; -}; - /* Macros for the SPI controller read/write */ static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) { @@ -469,64 +465,6 @@ static int cdns_unprepare_transfer_hardware(struct spi_master *master) return 0; } -static int cdns_spi_setup(struct spi_device *spi) -{ - - int ret = -EINVAL; - struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); - - /* this is a pin managed by the controller, leave it alone */ - if (spi->cs_gpio == -ENOENT) - return 0; - - /* this seems to be the first time we're here */ - if (!cdns_spi_data) { - cdns_spi_data = kzalloc(sizeof(*cdns_spi_data), GFP_KERNEL); - if (!cdns_spi_data) - return -ENOMEM; - cdns_spi_data->gpio_requested = false; - spi_set_ctldata(spi, cdns_spi_data); - } - - /* if we haven't done so, grab the gpio */ - if (!cdns_spi_data->gpio_requested && gpio_is_valid(spi->cs_gpio)) { - ret = gpio_request_one(spi->cs_gpio, - (spi->mode & SPI_CS_HIGH) ? - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, - dev_name(&spi->dev)); - if (ret) - dev_err(&spi->dev, "can't request chipselect gpio %d\n", - spi->cs_gpio); - else - cdns_spi_data->gpio_requested = true; - } else { - if (gpio_is_valid(spi->cs_gpio)) { - int mode = ((spi->mode & SPI_CS_HIGH) ? - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH); - - ret = gpio_direction_output(spi->cs_gpio, mode); - if (ret) - dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", - spi->cs_gpio, ret); - } - } - - return ret; -} - -static void cdns_spi_cleanup(struct spi_device *spi) -{ - struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); - - if (cdns_spi_data) { - if (cdns_spi_data->gpio_requested) - gpio_free(spi->cs_gpio); - kfree(cdns_spi_data); - spi_set_ctldata(spi, NULL); - } - -} - /** * cdns_spi_probe - Probe method for the SPI driver * @pdev: Pointer to the platform_device structure @@ -621,13 +559,12 @@ static int cdns_spi_probe(struct platform_device *pdev) goto clk_dis_all; } + master->use_gpio_descriptors = true; master->prepare_transfer_hardware = cdns_prepare_transfer_hardware; master->prepare_message = cdns_prepare_message; master->transfer_one = cdns_transfer_one; master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware; master->set_cs = cdns_spi_chipselect; - master->setup = cdns_spi_setup; - master->cleanup = cdns_spi_cleanup; master->auto_runtime_pm = true; master->mode_bits = SPI_CPOL | SPI_CPHA; -- cgit v1.2.3 From 054320b25520ff3c2440f5d56233c8f672293b3c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 7 Jan 2019 16:51:54 +0100 Subject: spi: clps711x: Convert to use CS GPIO descriptors This converts the CLPS711x SPI master driver to use GPIO descriptors for chip select handling. The CLPS711x driver was merely requesting the GPIO and setting the CS line non-asserted so this was a pretty straight-forward conversion. The setup callback goes away. Cc: Alexander Shiyan Cc: Linuxarm Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 18193df2eba8..8c03c409fc07 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -36,25 +36,6 @@ struct spi_clps711x_data { int len; }; -static int spi_clps711x_setup(struct spi_device *spi) -{ - if (!spi->controller_state) { - int ret; - - ret = devm_gpio_request(&spi->master->dev, spi->cs_gpio, - dev_name(&spi->master->dev)); - if (ret) - return ret; - - spi->controller_state = spi; - } - - /* We are expect that SPI-device is not selected */ - gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); - - return 0; -} - static int spi_clps711x_prepare_message(struct spi_master *master, struct spi_message *msg) { @@ -125,11 +106,11 @@ static int spi_clps711x_probe(struct platform_device *pdev) if (!master) return -ENOMEM; + master->use_gpio_descriptors = true; master->bus_num = -1; master->mode_bits = SPI_CPHA | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8); master->dev.of_node = pdev->dev.of_node; - master->setup = spi_clps711x_setup; master->prepare_message = spi_clps711x_prepare_message; master->transfer_one = spi_clps711x_transfer_one; -- cgit v1.2.3 From 101a68e74fe089b975c407f1bc9359882b05489a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 7 Jan 2019 16:51:55 +0100 Subject: spi: davinci: Convert to use CS GPIO descriptors This converts the DaVinci SPI master driver to use GPIO descriptors for chip select handling. DaVinci parses the device tree a second time for the chip select GPIOs (no relying on the parsing already happening in the SPI core) and handles inversion semantics locally. We simply drop the extra parsing and set up and move the CS handling to the core and gpiolib. The fact that the driver is actively driving the GPIO in the davinci_spi_chipselect() callback is confusing since the host does not set SPI_MASTER_GPIO_SS so this should not ever get called when using GPIO CS. I put in a comment about this. This driver also supports instantiation from board files, but these are all using native chip selects so no problem with GPIO lines here. Cc: David Lechner Cc: Bartosz Golaszewski Cc: Linuxarm Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 53 ++++++++++++----------------------------------- 1 file changed, 13 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 56adec83f8fc..5870afe3845b 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -222,12 +221,17 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) * Board specific chip select logic decides the polarity and cs * line for the controller */ - if (spi->cs_gpio >= 0) { + if (spi->cs_gpiod) { + /* + * FIXME: is this code ever executed? This host does not + * set SPI_MASTER_GPIO_SS so this chipselect callback should + * not get called from the SPI core when we are using + * GPIOs for chip select. + */ if (value == BITBANG_CS_ACTIVE) - gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH); + gpiod_set_value(spi->cs_gpiod, 1); else - gpio_set_value(spi->cs_gpio, - !(spi->mode & SPI_CS_HIGH)); + gpiod_set_value(spi->cs_gpiod, 0); } else { if (value == BITBANG_CS_ACTIVE) { if (!(spi->mode & SPI_CS_WORD)) @@ -418,7 +422,6 @@ static int davinci_spi_of_setup(struct spi_device *spi) */ static int davinci_spi_setup(struct spi_device *spi) { - int retval = 0; struct davinci_spi *dspi; struct spi_master *master = spi->master; struct device_node *np = spi->dev.of_node; @@ -427,21 +430,11 @@ static int davinci_spi_setup(struct spi_device *spi) dspi = spi_master_get_devdata(spi->master); if (!(spi->mode & SPI_NO_CS)) { - if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) { - retval = gpio_direction_output( - spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); + if (np && spi->cs_gpiod) internal_cs = false; - } - - if (retval) { - dev_err(&spi->dev, "GPIO %d setup failed (%d)\n", - spi->cs_gpio, retval); - return retval; - } - if (internal_cs) { + if (internal_cs) set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); - } } if (spi->mode & SPI_READY) @@ -962,6 +955,7 @@ static int davinci_spi_probe(struct platform_device *pdev) if (ret) goto free_master; + master->use_gpio_descriptors = true; master->dev.of_node = pdev->dev.of_node; master->bus_num = pdev->id; master->num_chipselect = pdata->num_chipselect; @@ -980,27 +974,6 @@ static int davinci_spi_probe(struct platform_device *pdev) if (dspi->version == SPI_VERSION_2) dspi->bitbang.flags |= SPI_READY; - if (pdev->dev.of_node) { - int i; - - for (i = 0; i < pdata->num_chipselect; i++) { - int cs_gpio = of_get_named_gpio(pdev->dev.of_node, - "cs-gpios", i); - - if (cs_gpio == -EPROBE_DEFER) { - ret = cs_gpio; - goto free_clk; - } - - if (gpio_is_valid(cs_gpio)) { - ret = devm_gpio_request(&pdev->dev, cs_gpio, - dev_name(&pdev->dev)); - if (ret) - goto free_clk; - } - } - } - dspi->bitbang.txrx_bufs = davinci_spi_bufs; ret = davinci_spi_request_dma(dspi); -- cgit v1.2.3 From 9400c41e77b8f1f9c711b08a6c79bdbc5681fb00 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 7 Jan 2019 16:51:56 +0100 Subject: spi: dw: Convert to use CS GPIO descriptors This converts the DesignWare (dw) SPI master driver to use GPIO descriptors for chip select handling. This driver has a duplicate DT parser in addition to the one in the core, sets up the line as non-asserted and relies on the core to drive the GPIOs. It is a pretty straight-forward conversion. Cc: Talel Shenhar Cc: Simon Goldschmidt Cc: Alexandre Belloni Cc: Linuxarm Tested-by: Jay Fang Reviewed-by: Alexandre Belloni Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mmio.c | 22 ---------------------- drivers/spi/spi-dw.c | 9 +-------- 2 files changed, 1 insertion(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index d0dd7814e997..4bd59a93d988 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -185,27 +184,6 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) dws->num_cs = num_cs; - if (pdev->dev.of_node) { - int i; - - for (i = 0; i < dws->num_cs; i++) { - int cs_gpio = of_get_named_gpio(pdev->dev.of_node, - "cs-gpios", i); - - if (cs_gpio == -EPROBE_DEFER) { - ret = cs_gpio; - goto out; - } - - if (gpio_is_valid(cs_gpio)) { - ret = devm_gpio_request(&pdev->dev, cs_gpio, - dev_name(&pdev->dev)); - if (ret) - goto out; - } - } - } - init_func = device_get_match_data(&pdev->dev); if (init_func) { ret = init_func(pdev, dwsmmio); diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index a945fad3db62..f54b498001a9 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "spi-dw.h" @@ -426,13 +425,6 @@ static int dw_spi_setup(struct spi_device *spi) chip->tmode = SPI_TMOD_TR; - if (gpio_is_valid(spi->cs_gpio)) { - ret = gpio_direction_output(spi->cs_gpio, - !(spi->mode & SPI_CS_HIGH)); - if (ret) - return ret; - } - return 0; } @@ -497,6 +489,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) goto err_free_master; } + master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); master->bus_num = dws->bus_num; -- cgit v1.2.3 From 69481059c507b3b5a99aaab0d544e6516034defc Mon Sep 17 00:00:00 2001 From: Hongye Yuan Date: Wed, 9 Jan 2019 09:18:08 +0800 Subject: HID: sony: Transform one-time SHANWAN check into quirk Transform the one-time check for a SHANWAN PS3 clone gamepad into a quirk, to avoid doing the same string comparison in multiple places. Signed-off-by: Hongye Yuan Reviewed-by: Bastien Nocera Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-sony.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 9671a4bad643..fc82f02bae75 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -58,6 +58,7 @@ #define FUTUREMAX_DANCE_MAT BIT(13) #define NSG_MR5U_REMOTE_BT BIT(14) #define NSG_MR7U_REMOTE_BT BIT(15) +#define SHANWAN_GAMEPAD BIT(16) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) @@ -1490,6 +1491,7 @@ static int sony_register_sensors(struct sony_sc *sc) */ static int sixaxis_set_operational_usb(struct hid_device *hdev) { + struct sony_sc *sc = hid_get_drvdata(hdev); const int buf_size = max(SIXAXIS_REPORT_0xF2_SIZE, SIXAXIS_REPORT_0xF5_SIZE); u8 *buf; @@ -1519,14 +1521,15 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) /* * But the USB interrupt would cause SHANWAN controllers to - * start rumbling non-stop. + * start rumbling non-stop, so skip step 3 for these controllers. */ - if (strcmp(hdev->name, "SHANWAN PS3 GamePad")) { - ret = hid_hw_output_report(hdev, buf, 1); - if (ret < 0) { - hid_info(hdev, "can't set operational mode: step 3, ignoring\n"); - ret = 0; - } + if (sc->quirks & SHANWAN_GAMEPAD) + goto out; + + ret = hid_hw_output_report(hdev, buf, 1); + if (ret < 0) { + hid_info(hdev, "can't set operational mode: step 3, ignoring\n"); + ret = 0; } out: @@ -2811,6 +2814,9 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) if (!strcmp(hdev->name, "FutureMax Dance Mat")) quirks |= FUTUREMAX_DANCE_MAT; + if (!strcmp(hdev->name, "SHANWAN PS3 GamePad")) + quirks |= SHANWAN_GAMEPAD; + sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); if (sc == NULL) { hid_err(hdev, "can't alloc sony descriptor\n"); -- cgit v1.2.3 From d03213f1287bcf3ad0102837694f021847737a0d Mon Sep 17 00:00:00 2001 From: Hongye Yuan Date: Wed, 9 Jan 2019 09:18:09 +0800 Subject: HID: sony: Fix SHANWAN PS3 GamePad rumble and led settings support Rumble support on SHANWAN PS3 gamepad is not working when a user program has asked it to. If a HID Output Reports is sent via Control Channel then it will be discard by gamepad, thus rumble motor and led settings in Output Report are ignored. This patch therefore sends HID Output Report via Interrupt Channel to SHANWAN gamepad instead of Control Channel, fixing rumble motor and led settings. Signed-off-by: Hongye Yuan Reviewed-by: Bastien Nocera Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-sony.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index fc82f02bae75..26fae90b931a 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -2100,9 +2100,14 @@ static void sixaxis_send_output_report(struct sony_sc *sc) } } - hid_hw_raw_request(sc->hdev, report->report_id, (u8 *)report, - sizeof(struct sixaxis_output_report), - HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); + /* SHANWAN controllers require output reports via intr channel */ + if (sc->quirks & SHANWAN_GAMEPAD) + hid_hw_output_report(sc->hdev, (u8 *)report, + sizeof(struct sixaxis_output_report)); + else + hid_hw_raw_request(sc->hdev, report->report_id, (u8 *)report, + sizeof(struct sixaxis_output_report), + HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); } static void dualshock4_send_output_report(struct sony_sc *sc) -- cgit v1.2.3 From b80ec7c0ef8de5d04b893310ecae29219143a454 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Fri, 7 Dec 2018 19:21:11 +0100 Subject: firmware: raspberrypi: notify VC4 firmware of a reboot The firmware-owned GPIO expander on RPi 3 B+ must be in same state after a reboot as initial power on. Otherwise this would cause a network boot failure of the BOOTROM. So inform the VC4 firmware to restore the expander before doing a reboot. Signed-off-by: Stefan Wahren Tested-by: Phil Elwell Reviewed-by: Eric Anholt --- drivers/firmware/raspberrypi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index a13558154ac3..61be15d9df7d 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -238,6 +238,16 @@ static int rpi_firmware_probe(struct platform_device *pdev) return 0; } +static void rpi_firmware_shutdown(struct platform_device *pdev) +{ + struct rpi_firmware *fw = platform_get_drvdata(pdev); + + if (!fw) + return; + + rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT, NULL, 0); +} + static int rpi_firmware_remove(struct platform_device *pdev) { struct rpi_firmware *fw = platform_get_drvdata(pdev); @@ -278,6 +288,7 @@ static struct platform_driver rpi_firmware_driver = { .of_match_table = rpi_firmware_of_match, }, .probe = rpi_firmware_probe, + .shutdown = rpi_firmware_shutdown, .remove = rpi_firmware_remove, }; module_platform_driver(rpi_firmware_driver); -- cgit v1.2.3 From 6f3656f3552a3b32c625c93ddafcbe10bf0fea6d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 22 Dec 2018 11:31:59 +0000 Subject: regulator: axp20x: check rdev is null before dereferencing it Currently rdev is dereferenced when assigning desc before rdev is null checked, hence there is a potential null pointer dereference on rdev. Fix this by null checking rdev first. Detected by CoverityScan, CID#1476031 ("Dereference before null check") Fixes: 77e3e3b165db ("regulator: axp20x: add software based soft_start for AXP209 LDO3") Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- drivers/regulator/axp20x-regulator.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 48af859fd053..0dfa4ea6bbdf 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -367,7 +367,7 @@ static const int axp209_dcdc2_ldo3_slew_rates[] = { static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp) { struct axp20x_dev *axp20x = rdev_get_drvdata(rdev); - const struct regulator_desc *desc = rdev->desc; + const struct regulator_desc *desc; u8 reg, mask, enable, cfg = 0xff; const int *slew_rates; int rate_count = 0; @@ -375,6 +375,8 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp) if (!rdev) return -EINVAL; + desc = rdev->desc; + switch (axp20x->variant) { case AXP209_ID: if (desc->id == AXP20X_DCDC2) { @@ -436,11 +438,13 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp) static int axp20x_regulator_enable_regmap(struct regulator_dev *rdev) { struct axp20x_dev *axp20x = rdev_get_drvdata(rdev); - const struct regulator_desc *desc = rdev->desc; + const struct regulator_desc *desc; if (!rdev) return -EINVAL; + desc = rdev->desc; + switch (axp20x->variant) { case AXP209_ID: if ((desc->id == AXP20X_LDO3) && -- cgit v1.2.3 From 5e6acc3e678ed3db746ab4fb53a980861cd711b6 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 12 Dec 2018 15:51:47 -0800 Subject: bcm2835-pm: Move bcm2835-watchdog's DT probe to an MFD. The PM block that the wdt driver was binding to actually has multiple features we want to expose (power domains, reset, watchdog). Move the DT attachment to a MFD driver and make WDT probe against MFD. Signed-off-by: Eric Anholt Reviewed-by: Guenter Roeck Acked-by: Stefan Wahren Signed-off-by: Stefan Wahren --- drivers/mfd/Makefile | 1 + drivers/mfd/bcm2835-pm.c | 64 ++++++++++++++++++++++++++++++++++++++++++ drivers/watchdog/bcm2835_wdt.c | 26 ++++++----------- 3 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 drivers/mfd/bcm2835-pm.c (limited to 'drivers') diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 12980a4ad460..ee6fb6af655e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_ACT8945A) += act8945a.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o +obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o cros_ec_core-objs := cros_ec.o diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c new file mode 100644 index 000000000000..53839e6a81e7 --- /dev/null +++ b/drivers/mfd/bcm2835-pm.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PM MFD driver for Broadcom BCM2835 + * + * This driver binds to the PM block and creates the MFD device for + * the WDT driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell bcm2835_pm_devs[] = { + { .name = "bcm2835-wdt" }, +}; + +static int bcm2835_pm_probe(struct platform_device *pdev) +{ + struct resource *res; + struct device *dev = &pdev->dev; + struct bcm2835_pm *pm; + + pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL); + if (!pm) + return -ENOMEM; + platform_set_drvdata(pdev, pm); + + pm->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pm->base = devm_ioremap_resource(dev, res); + if (IS_ERR(pm->base)) + return PTR_ERR(pm->base); + + return devm_mfd_add_devices(dev, -1, + bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs), + NULL, 0, NULL); +} + +static const struct of_device_id bcm2835_pm_of_match[] = { + { .compatible = "brcm,bcm2835-pm-wdt", }, + {}, +}; +MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match); + +static struct platform_driver bcm2835_pm_driver = { + .probe = bcm2835_pm_probe, + .driver = { + .name = "bcm2835-pm", + .of_match_table = bcm2835_pm_of_match, + }, +}; +module_platform_driver(bcm2835_pm_driver); + +MODULE_AUTHOR("Eric Anholt "); +MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM MFD"); +MODULE_LICENSE("GPL"); diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index ed05514cc2dc..1834524ae373 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,8 @@ struct bcm2835_wdt { spinlock_t lock; }; +static struct bcm2835_wdt *bcm2835_power_off_wdt; + static unsigned int heartbeat; static bool nowayout = WATCHDOG_NOWAYOUT; @@ -148,10 +151,7 @@ static struct watchdog_device bcm2835_wdt_wdd = { */ static void bcm2835_power_off(void) { - struct device_node *np = - of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt"); - struct platform_device *pdev = of_find_device_by_node(np); - struct bcm2835_wdt *wdt = platform_get_drvdata(pdev); + struct bcm2835_wdt *wdt = bcm2835_power_off_wdt; u32 val; /* @@ -169,7 +169,7 @@ static void bcm2835_power_off(void) static int bcm2835_wdt_probe(struct platform_device *pdev) { - struct resource *res; + struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent); struct device *dev = &pdev->dev; struct bcm2835_wdt *wdt; int err; @@ -181,10 +181,7 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) spin_lock_init(&wdt->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - wdt->base = devm_ioremap_resource(dev, res); - if (IS_ERR(wdt->base)) - return PTR_ERR(wdt->base); + wdt->base = pm->base; watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt); watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); @@ -211,8 +208,10 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) return err; } - if (pm_power_off == NULL) + if (pm_power_off == NULL) { pm_power_off = bcm2835_power_off; + bcm2835_power_off_wdt = wdt; + } dev_info(dev, "Broadcom BCM2835 watchdog timer"); return 0; @@ -226,18 +225,11 @@ static int bcm2835_wdt_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id bcm2835_wdt_of_match[] = { - { .compatible = "brcm,bcm2835-pm-wdt", }, - {}, -}; -MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match); - static struct platform_driver bcm2835_wdt_driver = { .probe = bcm2835_wdt_probe, .remove = bcm2835_wdt_remove, .driver = { .name = "bcm2835-wdt", - .of_match_table = bcm2835_wdt_of_match, }, }; module_platform_driver(bcm2835_wdt_driver); -- cgit v1.2.3 From 670c672608a1ffcbc7ac0f872734843593bb8b15 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 12 Dec 2018 15:51:48 -0800 Subject: soc: bcm: bcm2835-pm: Add support for power domains under a new binding. This provides a free software alternative to raspberrypi-power.c's firmware calls to manage power domains. It also exposes a reset line, where previously the vc4 driver had to try to force power off the domain in order to trigger a reset. Signed-off-by: Eric Anholt Acked-by: Rob Herring Acked-by: Stefan Wahren Signed-off-by: Stefan Wahren --- drivers/mfd/bcm2835-pm.c | 36 ++- drivers/soc/bcm/Kconfig | 11 + drivers/soc/bcm/Makefile | 1 + drivers/soc/bcm/bcm2835-power.c | 661 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 705 insertions(+), 4 deletions(-) create mode 100644 drivers/soc/bcm/bcm2835-power.c (limited to 'drivers') diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c index 53839e6a81e7..42fe67f1538e 100644 --- a/drivers/mfd/bcm2835-pm.c +++ b/drivers/mfd/bcm2835-pm.c @@ -3,7 +3,7 @@ * PM MFD driver for Broadcom BCM2835 * * This driver binds to the PM block and creates the MFD device for - * the WDT driver. + * the WDT and power drivers. */ #include @@ -21,11 +21,16 @@ static const struct mfd_cell bcm2835_pm_devs[] = { { .name = "bcm2835-wdt" }, }; +static const struct mfd_cell bcm2835_power_devs[] = { + { .name = "bcm2835-power" }, +}; + static int bcm2835_pm_probe(struct platform_device *pdev) { struct resource *res; struct device *dev = &pdev->dev; struct bcm2835_pm *pm; + int ret; pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL); if (!pm) @@ -39,13 +44,36 @@ static int bcm2835_pm_probe(struct platform_device *pdev) if (IS_ERR(pm->base)) return PTR_ERR(pm->base); - return devm_mfd_add_devices(dev, -1, - bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs), - NULL, 0, NULL); + ret = devm_mfd_add_devices(dev, -1, + bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs), + NULL, 0, NULL); + if (ret) + return ret; + + /* We'll use the presence of the AXI ASB regs in the + * bcm2835-pm binding as the key for whether we can reference + * the full PM register range and support power domains. + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + pm->asb = devm_ioremap_resource(dev, res); + if (IS_ERR(pm->asb)) + return PTR_ERR(pm->asb); + + ret = devm_mfd_add_devices(dev, -1, + bcm2835_power_devs, + ARRAY_SIZE(bcm2835_power_devs), + NULL, 0, NULL); + if (ret) + return ret; + } + + return 0; } static const struct of_device_id bcm2835_pm_of_match[] = { { .compatible = "brcm,bcm2835-pm-wdt", }, + { .compatible = "brcm,bcm2835-pm", }, {}, }; MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match); diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig index 055a845ed979..fe1af29560e9 100644 --- a/drivers/soc/bcm/Kconfig +++ b/drivers/soc/bcm/Kconfig @@ -1,5 +1,16 @@ menu "Broadcom SoC drivers" +config BCM2835_POWER + bool "BCM2835 power domain driver" + depends on ARCH_BCM2835 || (COMPILE_TEST && OF) + select PM_GENERIC_DOMAINS if PM + select RESET_CONTROLLER + help + This enables support for the BCM2835 power domains and reset + controller. Any usage of power domains by the Raspberry Pi + firmware means that Linux usage of the same power domain + must be accessed using the RASPBERRYPI_POWER driver + config RASPBERRYPI_POWER bool "Raspberry Pi power domain driver" depends on ARCH_BCM2835 || (COMPILE_TEST && OF) diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile index dc4fced72d21..c81df4b2403c 100644 --- a/drivers/soc/bcm/Makefile +++ b/drivers/soc/bcm/Makefile @@ -1,2 +1,3 @@ +obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/ diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c new file mode 100644 index 000000000000..48412957ec7a --- /dev/null +++ b/drivers/soc/bcm/bcm2835-power.c @@ -0,0 +1,661 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Power domain driver for Broadcom BCM2835 + * + * Copyright (C) 2018 Broadcom + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PM_GNRIC 0x00 +#define PM_AUDIO 0x04 +#define PM_STATUS 0x18 +#define PM_RSTC 0x1c +#define PM_RSTS 0x20 +#define PM_WDOG 0x24 +#define PM_PADS0 0x28 +#define PM_PADS2 0x2c +#define PM_PADS3 0x30 +#define PM_PADS4 0x34 +#define PM_PADS5 0x38 +#define PM_PADS6 0x3c +#define PM_CAM0 0x44 +#define PM_CAM0_LDOHPEN BIT(2) +#define PM_CAM0_LDOLPEN BIT(1) +#define PM_CAM0_CTRLEN BIT(0) + +#define PM_CAM1 0x48 +#define PM_CAM1_LDOHPEN BIT(2) +#define PM_CAM1_LDOLPEN BIT(1) +#define PM_CAM1_CTRLEN BIT(0) + +#define PM_CCP2TX 0x4c +#define PM_CCP2TX_LDOEN BIT(1) +#define PM_CCP2TX_CTRLEN BIT(0) + +#define PM_DSI0 0x50 +#define PM_DSI0_LDOHPEN BIT(2) +#define PM_DSI0_LDOLPEN BIT(1) +#define PM_DSI0_CTRLEN BIT(0) + +#define PM_DSI1 0x54 +#define PM_DSI1_LDOHPEN BIT(2) +#define PM_DSI1_LDOLPEN BIT(1) +#define PM_DSI1_CTRLEN BIT(0) + +#define PM_HDMI 0x58 +#define PM_HDMI_RSTDR BIT(19) +#define PM_HDMI_LDOPD BIT(1) +#define PM_HDMI_CTRLEN BIT(0) + +#define PM_USB 0x5c +/* The power gates must be enabled with this bit before enabling the LDO in the + * USB block. + */ +#define PM_USB_CTRLEN BIT(0) + +#define PM_PXLDO 0x60 +#define PM_PXBG 0x64 +#define PM_DFT 0x68 +#define PM_SMPS 0x6c +#define PM_XOSC 0x70 +#define PM_SPAREW 0x74 +#define PM_SPARER 0x78 +#define PM_AVS_RSTDR 0x7c +#define PM_AVS_STAT 0x80 +#define PM_AVS_EVENT 0x84 +#define PM_AVS_INTEN 0x88 +#define PM_DUMMY 0xfc + +#define PM_IMAGE 0x108 +#define PM_GRAFX 0x10c +#define PM_PROC 0x110 +#define PM_ENAB BIT(12) +#define PM_ISPRSTN BIT(8) +#define PM_H264RSTN BIT(7) +#define PM_PERIRSTN BIT(6) +#define PM_V3DRSTN BIT(6) +#define PM_ISFUNC BIT(5) +#define PM_MRDONE BIT(4) +#define PM_MEMREP BIT(3) +#define PM_ISPOW BIT(2) +#define PM_POWOK BIT(1) +#define PM_POWUP BIT(0) +#define PM_INRUSH_SHIFT 13 +#define PM_INRUSH_3_5_MA 0 +#define PM_INRUSH_5_MA 1 +#define PM_INRUSH_10_MA 2 +#define PM_INRUSH_20_MA 3 +#define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT) + +#define PM_PASSWORD 0x5a000000 + +#define PM_WDOG_TIME_SET 0x000fffff +#define PM_RSTC_WRCFG_CLR 0xffffffcf +#define PM_RSTS_HADWRH_SET 0x00000040 +#define PM_RSTC_WRCFG_SET 0x00000030 +#define PM_RSTC_WRCFG_FULL_RESET 0x00000020 +#define PM_RSTC_RESET 0x00000102 + +#define PM_READ(reg) readl(power->base + (reg)) +#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg)) + +#define ASB_BRDG_VERSION 0x00 +#define ASB_CPR_CTRL 0x04 + +#define ASB_V3D_S_CTRL 0x08 +#define ASB_V3D_M_CTRL 0x0c +#define ASB_ISP_S_CTRL 0x10 +#define ASB_ISP_M_CTRL 0x14 +#define ASB_H264_S_CTRL 0x18 +#define ASB_H264_M_CTRL 0x1c + +#define ASB_REQ_STOP BIT(0) +#define ASB_ACK BIT(1) +#define ASB_EMPTY BIT(2) +#define ASB_FULL BIT(3) + +#define ASB_AXI_BRDG_ID 0x20 + +#define ASB_READ(reg) readl(power->asb + (reg)) +#define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg)) + +struct bcm2835_power_domain { + struct generic_pm_domain base; + struct bcm2835_power *power; + u32 domain; + struct clk *clk; +}; + +struct bcm2835_power { + struct device *dev; + /* PM registers. */ + void __iomem *base; + /* AXI Async bridge registers. */ + void __iomem *asb; + + struct genpd_onecell_data pd_xlate; + struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT]; + struct reset_controller_dev reset; +}; + +static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg) +{ + u64 start = ktime_get_ns(); + + /* Enable the module's async AXI bridges. */ + ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP); + while (ASB_READ(reg) & ASB_ACK) { + cpu_relax(); + if (ktime_get_ns() - start >= 1000) + return -ETIMEDOUT; + } + + return 0; +} + +static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg) +{ + u64 start = ktime_get_ns(); + + /* Enable the module's async AXI bridges. */ + ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP); + while (!(ASB_READ(reg) & ASB_ACK)) { + cpu_relax(); + if (ktime_get_ns() - start >= 1000) + return -ETIMEDOUT; + } + + return 0; +} + +static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg) +{ + struct bcm2835_power *power = pd->power; + + /* Enable functional isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC); + + /* Enable electrical isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW); + + /* Open the power switches. */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP); + + return 0; +} + +static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg) +{ + struct bcm2835_power *power = pd->power; + struct device *dev = power->dev; + u64 start; + int ret; + int inrush; + bool powok; + + /* If it was already powered on by the fw, leave it that way. */ + if (PM_READ(pm_reg) & PM_POWUP) + return 0; + + /* Enable power. Allowing too much current at once may result + * in POWOK never getting set, so start low and ramp it up as + * necessary to succeed. + */ + powok = false; + for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) { + PM_WRITE(pm_reg, + (PM_READ(pm_reg) & ~PM_INRUSH_MASK) | + (inrush << PM_INRUSH_SHIFT) | + PM_POWUP); + + start = ktime_get_ns(); + while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) { + cpu_relax(); + if (ktime_get_ns() - start >= 3000) + break; + } + } + if (!powok) { + dev_err(dev, "Timeout waiting for %s power OK\n", + pd->base.name); + ret = -ETIMEDOUT; + goto err_disable_powup; + } + + /* Disable electrical isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW); + + /* Repair memory */ + PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP); + start = ktime_get_ns(); + while (!(PM_READ(pm_reg) & PM_MRDONE)) { + cpu_relax(); + if (ktime_get_ns() - start >= 1000) { + dev_err(dev, "Timeout waiting for %s memory repair\n", + pd->base.name); + ret = -ETIMEDOUT; + goto err_disable_ispow; + } + } + + /* Disable functional isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC); + + return 0; + +err_disable_ispow: + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW); +err_disable_powup: + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK)); + return ret; +} + +static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd, + u32 pm_reg, + u32 asb_m_reg, + u32 asb_s_reg, + u32 reset_flags) +{ + struct bcm2835_power *power = pd->power; + int ret; + + ret = clk_prepare_enable(pd->clk); + if (ret) { + dev_err(power->dev, "Failed to enable clock for %s\n", + pd->base.name); + return ret; + } + + /* Wait 32 clocks for reset to propagate, 1 us will be enough */ + udelay(1); + + clk_disable_unprepare(pd->clk); + + /* Deassert the resets. */ + PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags); + + ret = clk_prepare_enable(pd->clk); + if (ret) { + dev_err(power->dev, "Failed to enable clock for %s\n", + pd->base.name); + goto err_enable_resets; + } + + ret = bcm2835_asb_enable(power, asb_m_reg); + if (ret) { + dev_err(power->dev, "Failed to enable ASB master for %s\n", + pd->base.name); + goto err_disable_clk; + } + ret = bcm2835_asb_enable(power, asb_s_reg); + if (ret) { + dev_err(power->dev, "Failed to enable ASB slave for %s\n", + pd->base.name); + goto err_disable_asb_master; + } + + return 0; + +err_disable_asb_master: + bcm2835_asb_disable(power, asb_m_reg); +err_disable_clk: + clk_disable_unprepare(pd->clk); +err_enable_resets: + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags); + return ret; +} + +static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd, + u32 pm_reg, + u32 asb_m_reg, + u32 asb_s_reg, + u32 reset_flags) +{ + struct bcm2835_power *power = pd->power; + int ret; + + ret = bcm2835_asb_disable(power, asb_s_reg); + if (ret) { + dev_warn(power->dev, "Failed to disable ASB slave for %s\n", + pd->base.name); + return ret; + } + ret = bcm2835_asb_disable(power, asb_m_reg); + if (ret) { + dev_warn(power->dev, "Failed to disable ASB master for %s\n", + pd->base.name); + bcm2835_asb_enable(power, asb_s_reg); + return ret; + } + + clk_disable_unprepare(pd->clk); + + /* Assert the resets. */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags); + + return 0; +} + +static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain) +{ + struct bcm2835_power_domain *pd = + container_of(domain, struct bcm2835_power_domain, base); + struct bcm2835_power *power = pd->power; + + switch (pd->domain) { + case BCM2835_POWER_DOMAIN_GRAFX: + return bcm2835_power_power_on(pd, PM_GRAFX); + + case BCM2835_POWER_DOMAIN_GRAFX_V3D: + return bcm2835_asb_power_on(pd, PM_GRAFX, + ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, + PM_V3DRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE: + return bcm2835_power_power_on(pd, PM_IMAGE); + + case BCM2835_POWER_DOMAIN_IMAGE_PERI: + return bcm2835_asb_power_on(pd, PM_IMAGE, + 0, 0, + PM_PERIRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE_ISP: + return bcm2835_asb_power_on(pd, PM_IMAGE, + ASB_ISP_M_CTRL, ASB_ISP_S_CTRL, + PM_ISPRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE_H264: + return bcm2835_asb_power_on(pd, PM_IMAGE, + ASB_H264_M_CTRL, ASB_H264_S_CTRL, + PM_H264RSTN); + + case BCM2835_POWER_DOMAIN_USB: + PM_WRITE(PM_USB, PM_USB_CTRLEN); + return 0; + + case BCM2835_POWER_DOMAIN_DSI0: + PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN); + PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN); + return 0; + + case BCM2835_POWER_DOMAIN_DSI1: + PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN); + PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN); + return 0; + + case BCM2835_POWER_DOMAIN_CCP2TX: + PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN); + PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN); + return 0; + + case BCM2835_POWER_DOMAIN_HDMI: + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR); + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN); + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD); + usleep_range(100, 200); + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR); + return 0; + + default: + dev_err(power->dev, "Invalid domain %d\n", pd->domain); + return -EINVAL; + } +} + +static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain) +{ + struct bcm2835_power_domain *pd = + container_of(domain, struct bcm2835_power_domain, base); + struct bcm2835_power *power = pd->power; + + switch (pd->domain) { + case BCM2835_POWER_DOMAIN_GRAFX: + return bcm2835_power_power_off(pd, PM_GRAFX); + + case BCM2835_POWER_DOMAIN_GRAFX_V3D: + return bcm2835_asb_power_off(pd, PM_GRAFX, + ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, + PM_V3DRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE: + return bcm2835_power_power_off(pd, PM_IMAGE); + + case BCM2835_POWER_DOMAIN_IMAGE_PERI: + return bcm2835_asb_power_off(pd, PM_IMAGE, + 0, 0, + PM_PERIRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE_ISP: + return bcm2835_asb_power_off(pd, PM_IMAGE, + ASB_ISP_M_CTRL, ASB_ISP_S_CTRL, + PM_ISPRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE_H264: + return bcm2835_asb_power_off(pd, PM_IMAGE, + ASB_H264_M_CTRL, ASB_H264_S_CTRL, + PM_H264RSTN); + + case BCM2835_POWER_DOMAIN_USB: + PM_WRITE(PM_USB, 0); + return 0; + + case BCM2835_POWER_DOMAIN_DSI0: + PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN); + PM_WRITE(PM_DSI0, 0); + return 0; + + case BCM2835_POWER_DOMAIN_DSI1: + PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN); + PM_WRITE(PM_DSI1, 0); + return 0; + + case BCM2835_POWER_DOMAIN_CCP2TX: + PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN); + PM_WRITE(PM_CCP2TX, 0); + return 0; + + case BCM2835_POWER_DOMAIN_HDMI: + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD); + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN); + return 0; + + default: + dev_err(power->dev, "Invalid domain %d\n", pd->domain); + return -EINVAL; + } +} + +static void +bcm2835_init_power_domain(struct bcm2835_power *power, + int pd_xlate_index, const char *name) +{ + struct device *dev = power->dev; + struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index]; + + dom->clk = devm_clk_get(dev->parent, name); + + dom->base.name = name; + dom->base.power_on = bcm2835_power_pd_power_on; + dom->base.power_off = bcm2835_power_pd_power_off; + + dom->domain = pd_xlate_index; + dom->power = power; + + /* XXX: on/off at boot? */ + pm_genpd_init(&dom->base, NULL, true); + + power->pd_xlate.domains[pd_xlate_index] = &dom->base; +} + +/** bcm2835_reset_reset - Resets a block that has a reset line in the + * PM block. + * + * The consumer of the reset controller must have the power domain up + * -- there's no reset ability with the power domain down. To reset + * the sub-block, we just disable its access to memory through the + * ASB, reset, and re-enable. + */ +static int bcm2835_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power, + reset); + struct bcm2835_power_domain *pd; + int ret; + + switch (id) { + case BCM2835_RESET_V3D: + pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D]; + break; + case BCM2835_RESET_H264: + pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264]; + break; + case BCM2835_RESET_ISP: + pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP]; + break; + default: + dev_err(power->dev, "Bad reset id %ld\n", id); + return -EINVAL; + } + + ret = bcm2835_power_pd_power_off(&pd->base); + if (ret) + return ret; + + return bcm2835_power_pd_power_on(&pd->base); +} + +static int bcm2835_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power, + reset); + + switch (id) { + case BCM2835_RESET_V3D: + return !PM_READ(PM_GRAFX & PM_V3DRSTN); + case BCM2835_RESET_H264: + return !PM_READ(PM_IMAGE & PM_H264RSTN); + case BCM2835_RESET_ISP: + return !PM_READ(PM_IMAGE & PM_ISPRSTN); + default: + return -EINVAL; + } +} + +const struct reset_control_ops bcm2835_reset_ops = { + .reset = bcm2835_reset_reset, + .status = bcm2835_reset_status, +}; + +static const char *const power_domain_names[] = { + [BCM2835_POWER_DOMAIN_GRAFX] = "grafx", + [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d", + + [BCM2835_POWER_DOMAIN_IMAGE] = "image", + [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image", + [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264", + [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp", + + [BCM2835_POWER_DOMAIN_USB] = "usb", + [BCM2835_POWER_DOMAIN_DSI0] = "dsi0", + [BCM2835_POWER_DOMAIN_DSI1] = "dsi1", + [BCM2835_POWER_DOMAIN_CAM0] = "cam0", + [BCM2835_POWER_DOMAIN_CAM1] = "cam1", + [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx", + [BCM2835_POWER_DOMAIN_HDMI] = "hdmi", +}; + +static int bcm2835_power_probe(struct platform_device *pdev) +{ + struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct bcm2835_power *power; + static const struct { + int parent, child; + } domain_deps[] = { + { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D }, + { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI }, + { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 }, + { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP }, + { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB }, + { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 }, + { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 }, + }; + int ret, i; + u32 id; + + power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL); + if (!power) + return -ENOMEM; + platform_set_drvdata(pdev, power); + + power->dev = dev; + power->base = pm->base; + power->asb = pm->asb; + + id = ASB_READ(ASB_AXI_BRDG_ID); + if (id != 0x62726467 /* "BRDG" */) { + dev_err(dev, "ASB register ID returned 0x%08x\n", id); + return -ENODEV; + } + + power->pd_xlate.domains = devm_kcalloc(dev, + ARRAY_SIZE(power_domain_names), + sizeof(*power->pd_xlate.domains), + GFP_KERNEL); + if (!power->pd_xlate.domains) + return -ENOMEM; + + power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names); + + for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) + bcm2835_init_power_domain(power, i, power_domain_names[i]); + + for (i = 0; i < ARRAY_SIZE(domain_deps); i++) { + pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base, + &power->domains[domain_deps[i].child].base); + } + + power->reset.owner = THIS_MODULE; + power->reset.nr_resets = BCM2835_RESET_COUNT; + power->reset.ops = &bcm2835_reset_ops; + power->reset.of_node = dev->parent->of_node; + + ret = devm_reset_controller_register(dev, &power->reset); + if (ret) + return ret; + + of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate); + + dev_info(dev, "Broadcom BCM2835 power domains driver"); + return 0; +} + +static int bcm2835_power_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver bcm2835_power_driver = { + .probe = bcm2835_power_probe, + .remove = bcm2835_power_remove, + .driver = { + .name = "bcm2835-power", + }, +}; +module_platform_driver(bcm2835_power_driver); + +MODULE_AUTHOR("Eric Anholt "); +MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 03c87b95ac04c2a34045641b25dded6e3e889556 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 9 Jan 2019 18:44:00 +0100 Subject: regulator: provide rdev_get_regmap() Provide a helper allowing to access regulator's regmap. Signed-off-by: Bartosz Golaszewski Signed-off-by: Mark Brown --- drivers/regulator/core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 3f9d81b6e763..430a73dea487 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -5251,6 +5251,12 @@ struct device *rdev_get_dev(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(rdev_get_dev); +struct regmap *rdev_get_regmap(struct regulator_dev *rdev) +{ + return rdev->regmap; +} +EXPORT_SYMBOL_GPL(rdev_get_regmap); + void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) { return reg_init_data->driver_data; -- cgit v1.2.3 From 26fe27d9201bb0a5568325f053326671dad4412c Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Mon, 17 Dec 2018 19:12:14 -0700 Subject: clk: qcom: Add CLK_SET_RATE_PARENT for 8998 branch clocks A branch clock is basically a clock that can be gated for power savings, but is also what devices/drivers consume. Configuring a branch clock's rate needs to be done at the source, so for all branch clocks which have a defined parent, set CLK_SET_RATE_PARENT so that clk_set_rate() calls on branch clocks can do what is expected. This is important as most drivers do not check the resulting clock rate after a successful clk_set_rate() call, thus the driver may get out of sync with the actual hardware state and weird issues might crop up. This has been observed with issues getting SDHCI to reliably support "fast" cards such as SDR104. Fixes: 4807c71cc688 (arm64: dts: Add msm8998 SoC and MTP board support) Signed-off-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-msm8998.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index 1b779396e04f..b618bbfa9a7f 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -1189,6 +1189,7 @@ static struct clk_branch gcc_aggre1_ufs_axi_clk = { "ufs_axi_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1206,6 +1207,7 @@ static struct clk_branch gcc_aggre1_usb3_axi_clk = { "usb30_master_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1288,6 +1290,7 @@ static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { "blsp1_qup1_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1305,6 +1308,7 @@ static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { "blsp1_qup1_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1322,6 +1326,7 @@ static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { "blsp1_qup2_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1339,6 +1344,7 @@ static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { "blsp1_qup2_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1356,6 +1362,7 @@ static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { "blsp1_qup3_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1373,6 +1380,7 @@ static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { "blsp1_qup3_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1390,6 +1398,7 @@ static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { "blsp1_qup4_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1407,6 +1416,7 @@ static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { "blsp1_qup4_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1424,6 +1434,7 @@ static struct clk_branch gcc_blsp1_qup5_i2c_apps_clk = { "blsp1_qup5_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1441,6 +1452,7 @@ static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = { "blsp1_qup5_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1458,6 +1470,7 @@ static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = { "blsp1_qup6_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1475,6 +1488,7 @@ static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = { "blsp1_qup6_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1505,6 +1519,7 @@ static struct clk_branch gcc_blsp1_uart1_apps_clk = { "blsp1_uart1_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1522,6 +1537,7 @@ static struct clk_branch gcc_blsp1_uart2_apps_clk = { "blsp1_uart2_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1539,6 +1555,7 @@ static struct clk_branch gcc_blsp1_uart3_apps_clk = { "blsp1_uart3_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1569,6 +1586,7 @@ static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = { "blsp2_qup1_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1586,6 +1604,7 @@ static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = { "blsp2_qup1_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1603,6 +1622,7 @@ static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = { "blsp2_qup2_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1620,6 +1640,7 @@ static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = { "blsp2_qup2_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1637,6 +1658,7 @@ static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = { "blsp2_qup3_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1654,6 +1676,7 @@ static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = { "blsp2_qup3_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1671,6 +1694,7 @@ static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = { "blsp2_qup4_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1688,6 +1712,7 @@ static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = { "blsp2_qup4_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1705,6 +1730,7 @@ static struct clk_branch gcc_blsp2_qup5_i2c_apps_clk = { "blsp2_qup5_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1722,6 +1748,7 @@ static struct clk_branch gcc_blsp2_qup5_spi_apps_clk = { "blsp2_qup5_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1739,6 +1766,7 @@ static struct clk_branch gcc_blsp2_qup6_i2c_apps_clk = { "blsp2_qup6_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1756,6 +1784,7 @@ static struct clk_branch gcc_blsp2_qup6_spi_apps_clk = { "blsp2_qup6_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1786,6 +1815,7 @@ static struct clk_branch gcc_blsp2_uart1_apps_clk = { "blsp2_uart1_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1803,6 +1833,7 @@ static struct clk_branch gcc_blsp2_uart2_apps_clk = { "blsp2_uart2_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1820,6 +1851,7 @@ static struct clk_branch gcc_blsp2_uart3_apps_clk = { "blsp2_uart3_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1837,6 +1869,7 @@ static struct clk_branch gcc_cfg_noc_usb3_axi_clk = { "usb30_master_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1854,6 +1887,7 @@ static struct clk_branch gcc_gp1_clk = { "gp1_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1871,6 +1905,7 @@ static struct clk_branch gcc_gp2_clk = { "gp2_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1888,6 +1923,7 @@ static struct clk_branch gcc_gp3_clk = { "gp3_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1957,6 +1993,7 @@ static struct clk_branch gcc_hmss_ahb_clk = { "hmss_ahb_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1987,6 +2024,7 @@ static struct clk_branch gcc_hmss_rbcpr_clk = { "hmss_rbcpr_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2088,6 +2126,7 @@ static struct clk_branch gcc_pcie_0_aux_clk = { "pcie_aux_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2157,6 +2196,7 @@ static struct clk_branch gcc_pcie_phy_aux_clk = { "pcie_aux_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2174,6 +2214,7 @@ static struct clk_branch gcc_pdm2_clk = { "pdm2_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2243,6 +2284,7 @@ static struct clk_branch gcc_sdcc2_apps_clk = { "sdcc2_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2273,6 +2315,7 @@ static struct clk_branch gcc_sdcc4_apps_clk = { "sdcc4_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2316,6 +2359,7 @@ static struct clk_branch gcc_tsif_ref_clk = { "tsif_ref_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2346,6 +2390,7 @@ static struct clk_branch gcc_ufs_axi_clk = { "ufs_axi_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2441,6 +2486,7 @@ static struct clk_branch gcc_usb30_master_clk = { "usb30_master_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2458,6 +2504,7 @@ static struct clk_branch gcc_usb30_mock_utmi_clk = { "usb30_mock_utmi_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2488,6 +2535,7 @@ static struct clk_branch gcc_usb3_phy_aux_clk = { "usb3_phy_aux_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, -- cgit v1.2.3 From 0c8ff62504e3a667387e87889a259632c3199a86 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 4 Jan 2019 09:49:46 -0700 Subject: clk: qcom: Add missing freq for usb30_master_clk on 8998 The usb30_master_clk supports a 60Mhz frequency, but that is missing from the table of supported frequencies. Add it. Fixes: b5f5f525c547 (clk: qcom: Add MSM8998 Global Clock Control (GCC) driver) Signed-off-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-msm8998.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index b618bbfa9a7f..96cf00c425a8 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -1112,6 +1112,7 @@ static struct clk_rcg2 ufs_axi_clk_src = { static const struct freq_tbl ftbl_usb30_master_clk_src[] = { F(19200000, P_XO, 1, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), F(120000000, P_GPLL0_OUT_MAIN, 5, 0, 0), F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), { } -- cgit v1.2.3 From 5f2420ed218981f037910bd029c19ff35ad1839c Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 4 Jan 2019 09:50:15 -0700 Subject: clk: qcom: Skip halt checks on gcc_usb3_phy_pipe_clk for 8998 The gcc_usb3_phy_pipe_clk is generated by the phy, but is also used by the phy during init. The clock needs to be enabled during the init sequence, but may not be fully active until after the init sequence is complete. This causes a catch-22 if the clock status is checked during enable. As a result, skip the checks to avoid the troubling situation. Signed-off-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-msm8998.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index 96cf00c425a8..3cbabbb8bd9a 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -2544,7 +2544,7 @@ static struct clk_branch gcc_usb3_phy_aux_clk = { static struct clk_branch gcc_usb3_phy_pipe_clk = { .halt_reg = 0x50004, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x50004, .enable_mask = BIT(0), -- cgit v1.2.3 From 412e60373245fd1dfae8d4d44c5d1406b3d90971 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 8 Jan 2019 12:13:45 +0000 Subject: spi: core: avoid waking pump thread from spi_sync instead run teardown delayed When spi_sync is running alone with no other spi devices connected to the bus the worker thread is woken during spi_finalize_current_message to run the teardown code every time. This is totally unnecessary in the case that there is no message queued. On a multi-core system this results in one wakeup of the thread for each spi_message processed via spi_sync where in most cases the teardown does not happen as the hw is already in use. This patch now delays the teardown by 1 second by using a separate kthread_delayed_work for the teardown. This avoids waking the kthread too often. For spi_sync transfers in a tight loop (say 40k messages/s) this avoids the penalty of waking the worker thread 40k times/s. On a rasperry pi 3 with 4 cores the results in 32% of a single core only to find out that there is nothing in the queue and it can go back to sleep. With this patch applied the spi-worker is woken exactly once: after the load finishes and the spi bus is idle for 1 second. I believe I have also seen situations where during a spi_sync loop the worker thread (triggered by the last message finished) is slightly faster and _wins_ the race to process the message, so we are actually running the kthread and letting it do some work... This is also no longer observed with this patch applied as. Tested with a new CAN controller driver for the mcp2517fd which uses spi_sync for interrupt handling and spi_async for scheduling of can frames for transmission (in a different thread) Some statistics when receiving 100000 CAN frames with the mcp25xxfd driver on a Raspberry pi 3: without the patch: ------------------ root@raspcm3:~# for x in $(pgrep spi0) $(pgrep irq/94-mcp25xxf) ; do awk '{printf "%-20s %6i\n", $2,$15}' /proc/$x/stat; done (spi0) 5 (irq/94-mcp25xxf) 0 root@raspcm3:~# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 0 821960 13592 50848 0 0 80 2 1986 105 1 2 97 0 0 0 0 0 821968 13592 50876 0 0 0 0 8046 30 0 0 100 0 0 0 0 0 821936 13592 50876 0 0 0 0 8032 24 0 0 100 0 0 0 0 0 821936 13592 50876 0 0 0 0 8035 30 0 0 100 0 0 0 0 0 821936 13592 50876 0 0 0 0 8033 22 0 0 100 0 0 2 0 0 821936 13592 50876 0 0 0 0 11598 7129 0 3 97 0 0 1 0 0 821872 13592 50876 0 0 0 0 37741 59003 0 31 69 0 0 2 0 0 821840 13592 50876 0 0 0 0 37762 59078 0 29 71 0 0 2 0 0 821776 13592 50876 0 0 0 0 37593 58792 0 28 72 0 0 1 0 0 821744 13592 50876 0 0 0 0 37642 58881 0 30 70 0 0 2 0 0 821680 13592 50876 0 0 0 0 37490 58602 0 27 73 0 0 1 0 0 821648 13592 50876 0 0 0 0 37412 58418 0 29 71 0 0 1 0 0 821584 13592 50876 0 0 0 0 37337 58288 0 27 73 0 0 1 0 0 821552 13592 50876 0 0 0 0 37584 58774 0 27 73 0 0 0 0 0 821520 13592 50876 0 0 0 0 18363 20566 0 9 91 0 0 0 0 0 821520 13592 50876 0 0 0 0 8037 32 0 0 100 0 0 0 0 0 821520 13592 50876 0 0 0 0 8031 23 0 0 100 0 0 0 0 0 821520 13592 50876 0 0 0 0 8034 26 0 0 100 0 0 0 0 0 821520 13592 50876 0 0 0 0 8033 24 0 0 100 0 0 ^C root@raspcm3:~# for x in $(pgrep spi0) $(pgrep irq/94-mcp25xxf) ; do awk '{printf "%-20s %6i\n", $2,$15}' /proc/$x/stat; done (spi0) 228 (irq/94-mcp25xxf) 794 root@raspcm3:~# cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 17: 34 0 0 0 ARMCTRL-level 1 Edge 3f00b880.mailbox 27: 1 0 0 0 ARMCTRL-level 35 Edge timer 33: 1416870 0 0 0 ARMCTRL-level 41 Edge 3f980000.usb, dwc2_hsotg:usb1 34: 1 0 0 0 ARMCTRL-level 42 Edge vc4 35: 0 0 0 0 ARMCTRL-level 43 Edge 3f004000.txp 40: 1753 0 0 0 ARMCTRL-level 48 Edge DMA IRQ 42: 11 0 0 0 ARMCTRL-level 50 Edge DMA IRQ 44: 11 0 0 0 ARMCTRL-level 52 Edge DMA IRQ 45: 0 0 0 0 ARMCTRL-level 53 Edge DMA IRQ 66: 0 0 0 0 ARMCTRL-level 74 Edge vc4 crtc 69: 0 0 0 0 ARMCTRL-level 77 Edge vc4 crtc 70: 0 0 0 0 ARMCTRL-level 78 Edge vc4 crtc 77: 20 0 0 0 ARMCTRL-level 85 Edge 3f205000.i2c, 3f804000.i2c, 3f805000.i2c 78: 6346 0 0 0 ARMCTRL-level 86 Edge 3f204000.spi 80: 205 0 0 0 ARMCTRL-level 88 Edge mmc0 81: 493 0 0 0 ARMCTRL-level 89 Edge uart-pl011 89: 0 0 0 0 bcm2836-timer 0 Edge arch_timer 90: 4291 3821 2180 1649 bcm2836-timer 1 Edge arch_timer 94: 14289 0 0 0 pinctrl-bcm2835 16 Level mcp25xxfd IPI0: 0 0 0 0 CPU wakeup interrupts IPI1: 0 0 0 0 Timer broadcast interrupts IPI2: 3645 242371 7919 1328 Rescheduling interrupts IPI3: 112 543 273 194 Function call interrupts IPI4: 0 0 0 0 CPU stop interrupts IPI5: 1 0 0 0 IRQ work interrupts IPI6: 0 0 0 0 completion interrupts Err: 0 top shows 93% for the mcp25xxfd interrupt handler, 31% for spi0. with the patch: --------------- root@raspcm3:~# for x in $(pgrep spi0) $(pgrep irq/94-mcp25xxf) ; do awk '{printf "%-20s %6i\n", $2,$15}' /proc/$x/stat; done (spi0) 0 (irq/94-mcp25xxf) 0 root@raspcm3:~# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- 0 0 0 804768 13584 62628 0 0 0 0 8038 24 0 0 100 0 0 0 0 0 804768 13584 62628 0 0 0 0 8042 25 0 0 100 0 0 1 0 0 804704 13584 62628 0 0 0 0 9603 2967 0 20 80 0 0 1 0 0 804672 13584 62628 0 0 0 0 9828 3380 0 24 76 0 0 1 0 0 804608 13584 62628 0 0 0 0 9823 3375 0 23 77 0 0 1 0 0 804608 13584 62628 0 0 0 12 9829 3394 0 23 77 0 0 1 0 0 804544 13584 62628 0 0 0 0 9816 3362 0 22 78 0 0 1 0 0 804512 13584 62628 0 0 0 0 9817 3367 0 23 77 0 0 1 0 0 804448 13584 62628 0 0 0 0 9822 3370 0 22 78 0 0 1 0 0 804416 13584 62628 0 0 0 0 9815 3367 0 23 77 0 0 0 0 0 804352 13584 62628 0 0 0 84 9222 2250 0 14 86 0 0 0 0 0 804352 13592 62620 0 0 0 24 8131 209 0 0 93 7 0 0 0 0 804320 13592 62628 0 0 0 0 8041 27 0 0 100 0 0 0 0 0 804352 13592 62628 0 0 0 0 8040 26 0 0 100 0 0 root@raspcm3:~# for x in $(pgrep spi0) $(pgrep irq/94-mcp25xxf) ; do awk '{printf "%-20s %6i\n", $2,$15}' /proc/$x/stat; done (spi0) 0 (irq/94-mcp25xxf) 767 root@raspcm3:~# cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 17: 29 0 0 0 ARMCTRL-level 1 Edge 3f00b880.mailbox 27: 1 0 0 0 ARMCTRL-level 35 Edge timer 33: 1024412 0 0 0 ARMCTRL-level 41 Edge 3f980000.usb, dwc2_hsotg:usb1 34: 1 0 0 0 ARMCTRL-level 42 Edge vc4 35: 0 0 0 0 ARMCTRL-level 43 Edge 3f004000.txp 40: 1773 0 0 0 ARMCTRL-level 48 Edge DMA IRQ 42: 11 0 0 0 ARMCTRL-level 50 Edge DMA IRQ 44: 11 0 0 0 ARMCTRL-level 52 Edge DMA IRQ 45: 0 0 0 0 ARMCTRL-level 53 Edge DMA IRQ 66: 0 0 0 0 ARMCTRL-level 74 Edge vc4 crtc 69: 0 0 0 0 ARMCTRL-level 77 Edge vc4 crtc 70: 0 0 0 0 ARMCTRL-level 78 Edge vc4 crtc 77: 20 0 0 0 ARMCTRL-level 85 Edge 3f205000.i2c, 3f804000.i2c, 3f805000.i2c 78: 6417 0 0 0 ARMCTRL-level 86 Edge 3f204000.spi 80: 237 0 0 0 ARMCTRL-level 88 Edge mmc0 81: 489 0 0 0 ARMCTRL-level 89 Edge uart-pl011 89: 0 0 0 0 bcm2836-timer 0 Edge arch_timer 90: 4048 3704 2383 1892 bcm2836-timer 1 Edge arch_timer 94: 14287 0 0 0 pinctrl-bcm2835 16 Level mcp25xxfd IPI0: 0 0 0 0 CPU wakeup interrupts IPI1: 0 0 0 0 Timer broadcast interrupts IPI2: 2361 2948 7890 1616 Rescheduling interrupts IPI3: 65 617 301 166 Function call interrupts IPI4: 0 0 0 0 CPU stop interrupts IPI5: 1 0 0 0 IRQ work interrupts IPI6: 0 0 0 0 completion interrupts Err: 0 top shows 91% for the mcp25xxfd interrupt handler, 0% for spi0 So we see that spi0 is no longer getting scheduled wasting CPU cycles There are a lot less context switches and corresponding Rescheduling interrupts All of these show that this improves efficiency of the system and reduces CPU utilization. Signed-off-by: Martin Sperl Signed-off-by: Mark Brown --- drivers/spi/spi.c | 122 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 13f447a67d67..06b9139664a3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1225,7 +1225,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) return; } - /* If another context is idling the device then defer */ + /* If another context is idling the device then defer to kthread */ if (ctlr->idling) { kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); @@ -1239,34 +1239,10 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) return; } - /* Only do teardown in the thread */ - if (!in_kthread) { - kthread_queue_work(&ctlr->kworker, - &ctlr->pump_messages); - spin_unlock_irqrestore(&ctlr->queue_lock, flags); - return; - } - - ctlr->busy = false; - ctlr->idling = true; - spin_unlock_irqrestore(&ctlr->queue_lock, flags); - - kfree(ctlr->dummy_rx); - ctlr->dummy_rx = NULL; - kfree(ctlr->dummy_tx); - ctlr->dummy_tx = NULL; - if (ctlr->unprepare_transfer_hardware && - ctlr->unprepare_transfer_hardware(ctlr)) - dev_err(&ctlr->dev, - "failed to unprepare transfer hardware\n"); - if (ctlr->auto_runtime_pm) { - pm_runtime_mark_last_busy(ctlr->dev.parent); - pm_runtime_put_autosuspend(ctlr->dev.parent); - } - trace_spi_controller_idle(ctlr); - - spin_lock_irqsave(&ctlr->queue_lock, flags); - ctlr->idling = false; + /* schedule idle teardown with a delay of 1 second */ + kthread_mod_delayed_work(&ctlr->kworker, + &ctlr->pump_idle_teardown, + HZ); spin_unlock_irqrestore(&ctlr->queue_lock, flags); return; } @@ -1359,6 +1335,77 @@ static void spi_pump_messages(struct kthread_work *work) __spi_pump_messages(ctlr, true); } +/** + * spi_pump_idle_teardown - kthread delayed work function which tears down + * the controller settings after some delay + * @work: pointer to kthread work struct contained in the controller struct + */ +static void spi_pump_idle_teardown(struct kthread_work *work) +{ + struct spi_controller *ctlr = + container_of(work, struct spi_controller, + pump_idle_teardown.work); + unsigned long flags; + + /* Lock queue */ + spin_lock_irqsave(&ctlr->queue_lock, flags); + + /* Make sure we are not already running a message */ + if (ctlr->cur_msg) + goto out; + + /* if there is anything in the list then exit */ + if (!list_empty(&ctlr->queue)) + goto out; + + /* if the controller is running then exit */ + if (ctlr->running) + goto out; + + /* if the controller is busy then exit */ + if (ctlr->busy) + goto out; + + /* if the controller is idling then exit + * this is actually a bit strange and would indicate that + * this function is scheduled twice, which should not happen + */ + if (ctlr->idling) + goto out; + + /* set up the initial states */ + ctlr->busy = false; + ctlr->idling = true; + spin_unlock_irqrestore(&ctlr->queue_lock, flags); + + /* free dummy receive buffers */ + kfree(ctlr->dummy_rx); + ctlr->dummy_rx = NULL; + kfree(ctlr->dummy_tx); + ctlr->dummy_tx = NULL; + + /* unprepare hardware */ + if (ctlr->unprepare_transfer_hardware && + ctlr->unprepare_transfer_hardware(ctlr)) + dev_err(&ctlr->dev, + "failed to unprepare transfer hardware\n"); + /* handle pm */ + if (ctlr->auto_runtime_pm) { + pm_runtime_mark_last_busy(ctlr->dev.parent); + pm_runtime_put_autosuspend(ctlr->dev.parent); + } + + /* mark controller as idle */ + trace_spi_controller_idle(ctlr); + + /* finally put us from idling into stopped */ + spin_lock_irqsave(&ctlr->queue_lock, flags); + ctlr->idling = false; + +out: + spin_unlock_irqrestore(&ctlr->queue_lock, flags); +} + static int spi_init_queue(struct spi_controller *ctlr) { struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; @@ -1374,7 +1421,8 @@ static int spi_init_queue(struct spi_controller *ctlr) return PTR_ERR(ctlr->kworker_task); } kthread_init_work(&ctlr->pump_messages, spi_pump_messages); - + kthread_init_delayed_work(&ctlr->pump_idle_teardown, + spi_pump_idle_teardown); /* * Controller config will indicate if this controller should run the * message pump with high (realtime) priority to reduce the transfer @@ -1446,7 +1494,16 @@ void spi_finalize_current_message(struct spi_controller *ctlr) spin_lock_irqsave(&ctlr->queue_lock, flags); ctlr->cur_msg = NULL; ctlr->cur_msg_prepared = false; - kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + + /* if there is something queued, then wake the queue */ + if (!list_empty(&ctlr->queue)) + kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); + else + /* otherwise schedule delayed teardown */ + kthread_mod_delayed_work(&ctlr->kworker, + &ctlr->pump_idle_teardown, + HZ); + spin_unlock_irqrestore(&ctlr->queue_lock, flags); trace_spi_message_done(mesg); @@ -1551,7 +1608,7 @@ static int __spi_queued_transfer(struct spi_device *spi, msg->status = -EINPROGRESS; list_add_tail(&msg->queue, &ctlr->queue); - if (!ctlr->busy && need_pump) + if (need_pump) kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); @@ -3726,4 +3783,3 @@ err0: * include needing to have boardinfo data structures be much more public. */ postcore_initcall(spi_init); - -- cgit v1.2.3 From 50cc4caf531abb2075c6973451fccdaba9f02715 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 13 Dec 2018 12:49:29 +0000 Subject: clk: Add Fixed MMIO clock driver This patch adds a driver for Fixed MMIO clock. The driver reads a clock frequency value from a single 32-bit memory mapped register and registers it as a fixed rate clock. It can be enabled with COMMON_CLK_FIXED_MMIO Kconfig option. Signed-off-by: Jan Kotas [sboyd@kernel.org: Make of_fixed_mmio_clk_setup() static, use clk_hw based APIs] Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 6 +++ drivers/clk/Makefile | 1 + drivers/clk/clk-fixed-mmio.c | 101 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 drivers/clk/clk-fixed-mmio.c (limited to 'drivers') diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e5b2fe80eab4..296972518db4 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -290,6 +290,12 @@ config COMMON_CLK_BD718XX This driver supports ROHM BD71837 and ROHM BD71847 PMICs clock gates. +config COMMON_CLK_FIXED_MMIO + bool "Clock driver for Memory Mapped Fixed values" + depends on COMMON_CLK && OF + help + Support for Memory Mapped IO Fixed clocks + source "drivers/clk/actions/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 8a9440a97500..d6cd32bda771 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o +obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o diff --git a/drivers/clk/clk-fixed-mmio.c b/drivers/clk/clk-fixed-mmio.c new file mode 100644 index 000000000000..d1a97d971183 --- /dev/null +++ b/drivers/clk/clk-fixed-mmio.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Memory Mapped IO Fixed clock driver + * + * Copyright (C) 2018 Cadence Design Systems, Inc. + * + * Authors: + * Jan Kotas + */ + +#include +#include +#include +#include + +static struct clk_hw *fixed_mmio_clk_setup(struct device_node *node) +{ + struct clk_hw *clk; + const char *clk_name = node->name; + void __iomem *base; + u32 freq; + int ret; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%pOFn: failed to map address\n", node); + return ERR_PTR(-EIO); + } + + freq = readl(base); + iounmap(base); + of_property_read_string(node, "clock-output-names", &clk_name); + + clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0, freq); + if (IS_ERR(clk)) { + pr_err("%pOFn: failed to register fixed rate clock\n", node); + return clk; + } + + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, clk); + if (ret) { + pr_err("%pOFn: failed to add clock provider\n", node); + clk_hw_unregister(clk); + clk = ERR_PTR(ret); + } + + return clk; +} + +static void __init of_fixed_mmio_clk_setup(struct device_node *node) +{ + fixed_mmio_clk_setup(node); +} +CLK_OF_DECLARE(fixed_mmio_clk, "fixed-mmio-clock", of_fixed_mmio_clk_setup); + +/** + * This is not executed when of_fixed_mmio_clk_setup succeeded. + */ +static int of_fixed_mmio_clk_probe(struct platform_device *pdev) +{ + struct clk_hw *clk; + + clk = fixed_mmio_clk_setup(pdev->dev.of_node); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + platform_set_drvdata(pdev, clk); + + return 0; +} + +static int of_fixed_mmio_clk_remove(struct platform_device *pdev) +{ + struct clk_hw *clk = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + clk_hw_unregister_fixed_rate(clk); + + return 0; +} + +static const struct of_device_id of_fixed_mmio_clk_ids[] = { + { .compatible = "fixed-mmio-clock" }, + { } +}; +MODULE_DEVICE_TABLE(of, of_fixed_mmio_clk_ids); + +static struct platform_driver of_fixed_mmio_clk_driver = { + .driver = { + .name = "of_fixed_mmio_clk", + .of_match_table = of_fixed_mmio_clk_ids, + }, + .probe = of_fixed_mmio_clk_probe, + .remove = of_fixed_mmio_clk_remove, +}; +module_platform_driver(of_fixed_mmio_clk_driver); + +MODULE_AUTHOR("Jan Kotas "); +MODULE_DESCRIPTION("Memory Mapped IO Fixed clock driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6131dc81211cfcd8b7bd210665fbe0b6ba2e5fc5 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Mon, 17 Dec 2018 19:15:36 -0700 Subject: clk: qcom: smd: Add support for MSM8998 rpm clocks Add rpm smd clocks, PMIC and bus clocks which are required on MSM8998 for clients to vote on. Signed-off-by: Jeffrey Hugo Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-smd-rpm.c | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index d3aadaeb2903..22dd42ad9223 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -655,10 +655,73 @@ static const struct rpm_smd_clk_desc rpm_clk_qcs404 = { .num_clks = ARRAY_SIZE(qcs404_clks), }; +/* msm8998 */ +DEFINE_CLK_SMD_RPM(msm8998, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8998, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2); +DEFINE_CLK_SMD_RPM(msm8998, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, div_clk1, div_clk1_a, 0xb); +DEFINE_CLK_SMD_RPM(msm8998, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk1, ln_bb_clk1_a, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk2, ln_bb_clk2_a, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, ln_bb_clk3_pin, ln_bb_clk3_a_pin, + 3); +DEFINE_CLK_SMD_RPM(msm8998, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk, + QCOM_SMD_RPM_MMAXI_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8998, aggre1_noc_clk, aggre1_noc_a_clk, + QCOM_SMD_RPM_AGGR_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8998, aggre2_noc_clk, aggre2_noc_a_clk, + QCOM_SMD_RPM_AGGR_CLK, 2); +DEFINE_CLK_SMD_RPM_QDSS(msm8998, qdss_clk, qdss_a_clk, + QCOM_SMD_RPM_MISC_CLK, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk1, rf_clk1_a, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk2_pin, rf_clk2_a_pin, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk3, rf_clk3_a, 6); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk3_pin, rf_clk3_a_pin, 6); +static struct clk_smd_rpm *msm8998_clks[] = { + [RPM_SMD_SNOC_CLK] = &msm8998_snoc_clk, + [RPM_SMD_SNOC_A_CLK] = &msm8998_snoc_a_clk, + [RPM_SMD_CNOC_CLK] = &msm8998_cnoc_clk, + [RPM_SMD_CNOC_A_CLK] = &msm8998_cnoc_a_clk, + [RPM_SMD_CE1_CLK] = &msm8998_ce1_clk, + [RPM_SMD_CE1_A_CLK] = &msm8998_ce1_a_clk, + [RPM_SMD_DIV_CLK1] = &msm8998_div_clk1, + [RPM_SMD_DIV_A_CLK1] = &msm8998_div_clk1_a, + [RPM_SMD_IPA_CLK] = &msm8998_ipa_clk, + [RPM_SMD_IPA_A_CLK] = &msm8998_ipa_a_clk, + [RPM_SMD_LN_BB_CLK1] = &msm8998_ln_bb_clk1, + [RPM_SMD_LN_BB_CLK1_A] = &msm8998_ln_bb_clk1_a, + [RPM_SMD_LN_BB_CLK2] = &msm8998_ln_bb_clk2, + [RPM_SMD_LN_BB_CLK2_A] = &msm8998_ln_bb_clk2_a, + [RPM_SMD_LN_BB_CLK3_PIN] = &msm8998_ln_bb_clk3_pin, + [RPM_SMD_LN_BB_CLK3_A_PIN] = &msm8998_ln_bb_clk3_a_pin, + [RPM_SMD_MMAXI_CLK] = &msm8998_mmssnoc_axi_rpm_clk, + [RPM_SMD_MMAXI_A_CLK] = &msm8998_mmssnoc_axi_rpm_a_clk, + [RPM_SMD_AGGR1_NOC_CLK] = &msm8998_aggre1_noc_clk, + [RPM_SMD_AGGR1_NOC_A_CLK] = &msm8998_aggre1_noc_a_clk, + [RPM_SMD_AGGR2_NOC_CLK] = &msm8998_aggre2_noc_clk, + [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8998_aggre2_noc_a_clk, + [RPM_SMD_QDSS_CLK] = &msm8998_qdss_clk, + [RPM_SMD_QDSS_A_CLK] = &msm8998_qdss_a_clk, + [RPM_SMD_RF_CLK1] = &msm8998_rf_clk1, + [RPM_SMD_RF_CLK1_A] = &msm8998_rf_clk1_a, + [RPM_SMD_RF_CLK2_PIN] = &msm8998_rf_clk2_pin, + [RPM_SMD_RF_CLK2_A_PIN] = &msm8998_rf_clk2_a_pin, + [RPM_SMD_RF_CLK3] = &msm8998_rf_clk3, + [RPM_SMD_RF_CLK3_A] = &msm8998_rf_clk3_a, + [RPM_SMD_RF_CLK3_PIN] = &msm8998_rf_clk3_pin, + [RPM_SMD_RF_CLK3_A_PIN] = &msm8998_rf_clk3_a_pin, +}; + +static const struct rpm_smd_clk_desc rpm_clk_msm8998 = { + .clks = msm8998_clks, + .num_clks = ARRAY_SIZE(msm8998_clks), +}; + static const struct of_device_id rpm_smd_clk_match_table[] = { { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 }, { .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 }, + { .compatible = "qcom,rpmcc-msm8998", .data = &rpm_clk_msm8998 }, { .compatible = "qcom,rpmcc-qcs404", .data = &rpm_clk_qcs404 }, { } }; -- cgit v1.2.3 From 77977b800451ea7f438bf0398c76e56ef92379fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 18 Dec 2018 12:20:48 +0100 Subject: clk: at91: enable AUDIOPLL as source for PCKx on SAMA5D2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Datasheet for SAMA5D2x mentions 6 sources for PCKx, the last being AUDIOPLL. Signed-off-by: Michał Mirosław Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama5d2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index d69ad96fe988..ade063622531 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -241,13 +241,14 @@ static void __init sama5d2_pmc_setup(struct device_node *np) parent_names[2] = "plladivck"; parent_names[3] = "utmick"; parent_names[4] = "mck"; + parent_names[5] = "audiopll_pmcck"; for (i = 0; i < 3; i++) { char name[6]; snprintf(name, sizeof(name), "prog%d", i); hw = at91_clk_register_programmable(regmap, name, - parent_names, 5, i, + parent_names, 6, i, &at91sam9x5_programmable_layout); if (IS_ERR(hw)) goto err_free; -- cgit v1.2.3 From a77d087fd566f576da1f5b8726dd9d9f0f164e1f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 27 Nov 2018 09:11:15 -0800 Subject: lkdtm: Do not depend on BLOCK and clean up headers After the transition to kprobes, symbols are resolved at runtime. This means there is no need to have all the Kconfig and header logic to avoid build failures. This also paves the way to having arbitrary test locations. Reported-by: Christophe Leroy Signed-off-by: Kees Cook --- drivers/misc/lkdtm/core.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 2837dc77478e..5d41c2230d2e 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -37,16 +37,9 @@ #include #include #include -#include -#include #include -#include #include -#ifdef CONFIG_IDE -#include -#endif - #define DEFAULT_COUNT 10 static int lkdtm_debugfs_open(struct inode *inode, struct file *file); @@ -102,9 +95,7 @@ static struct crashpoint crashpoints[] = { CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"), CRASHPOINT("TIMERADD", "hrtimer_start"), CRASHPOINT("SCSI_DISPATCH_CMD", "scsi_dispatch_cmd"), -# ifdef CONFIG_IDE CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"), -# endif #endif }; -- cgit v1.2.3 From 4c411157a42f122051ae3469bee0b5cabe89e139 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 7 Nov 2018 20:14:10 +0000 Subject: lkdtm: Print real addresses Today, when doing a lkdtm test before the readiness of the random generator, (ptrval) is printed instead of the address at which it perform the fault: [ 1597.337030] lkdtm: Performing direct entry EXEC_USERSPACE [ 1597.337142] lkdtm: attempting ok execution at (ptrval) [ 1597.337398] lkdtm: attempting bad execution at (ptrval) [ 1597.337460] kernel tried to execute user page (77858000) -exploit attempt? (uid: 0) [ 1597.344769] Unable to handle kernel paging request for instruction fetch [ 1597.351392] Faulting instruction address: 0x77858000 [ 1597.356312] Oops: Kernel access of bad area, sig: 11 [#1] If the lkdtm test is done later on, it prints an hashed address. In both cases this is pointless. The purpose of the test is to ensure the kernel generates an Oops at the expected address, so real addresses needs to be printed. This patch fixes that. Signed-off-by: Christophe Leroy Signed-off-by: Kees Cook --- drivers/misc/lkdtm/perms.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c index 53b85c9d16b8..fa54add6375a 100644 --- a/drivers/misc/lkdtm/perms.c +++ b/drivers/misc/lkdtm/perms.c @@ -47,7 +47,7 @@ static noinline void execute_location(void *dst, bool write) { void (*func)(void) = dst; - pr_info("attempting ok execution at %p\n", do_nothing); + pr_info("attempting ok execution at %px\n", do_nothing); do_nothing(); if (write == CODE_WRITE) { @@ -55,7 +55,7 @@ static noinline void execute_location(void *dst, bool write) flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); } - pr_info("attempting bad execution at %p\n", func); + pr_info("attempting bad execution at %px\n", func); func(); } @@ -66,14 +66,14 @@ static void execute_user_location(void *dst) /* Intentionally crossing kernel/user memory boundary. */ void (*func)(void) = dst; - pr_info("attempting ok execution at %p\n", do_nothing); + pr_info("attempting ok execution at %px\n", do_nothing); do_nothing(); copied = access_process_vm(current, (unsigned long)dst, do_nothing, EXEC_SIZE, FOLL_WRITE); if (copied < EXEC_SIZE) return; - pr_info("attempting bad execution at %p\n", func); + pr_info("attempting bad execution at %px\n", func); func(); } @@ -82,7 +82,7 @@ void lkdtm_WRITE_RO(void) /* Explicitly cast away "const" for the test. */ unsigned long *ptr = (unsigned long *)&rodata; - pr_info("attempting bad rodata write at %p\n", ptr); + pr_info("attempting bad rodata write at %px\n", ptr); *ptr ^= 0xabcd1234; } @@ -100,7 +100,7 @@ void lkdtm_WRITE_RO_AFTER_INIT(void) return; } - pr_info("attempting bad ro_after_init write at %p\n", ptr); + pr_info("attempting bad ro_after_init write at %px\n", ptr); *ptr ^= 0xabcd1234; } @@ -112,7 +112,7 @@ void lkdtm_WRITE_KERN(void) size = (unsigned long)do_overwritten - (unsigned long)do_nothing; ptr = (unsigned char *)do_overwritten; - pr_info("attempting bad %zu byte write at %p\n", size, ptr); + pr_info("attempting bad %zu byte write at %px\n", size, ptr); memcpy(ptr, (unsigned char *)do_nothing, size); flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size)); @@ -185,11 +185,11 @@ void lkdtm_ACCESS_USERSPACE(void) ptr = (unsigned long *)user_addr; - pr_info("attempting bad read at %p\n", ptr); + pr_info("attempting bad read at %px\n", ptr); tmp = *ptr; tmp += 0xc0dec0de; - pr_info("attempting bad write at %p\n", ptr); + pr_info("attempting bad write at %px\n", ptr); *ptr = tmp; vm_munmap(user_addr, PAGE_SIZE); -- cgit v1.2.3 From 59a12205d3c32aee4c13ca36889fdf7cfed31126 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 14 Dec 2018 15:26:20 +0000 Subject: lkdtm: Add tests for NULL pointer dereference Introduce lkdtm tests for NULL pointer dereference: check access or exec at NULL address, since these errors tend to be reported differently from the general fault error text. For example from x86: pr_alert("BUG: unable to handle kernel %s at %px\n", address < PAGE_SIZE ? "NULL pointer dereference" : "paging request", (void *)address); Signed-off-by: Christophe Leroy Signed-off-by: Kees Cook --- drivers/misc/lkdtm/core.c | 2 ++ drivers/misc/lkdtm/lkdtm.h | 2 ++ drivers/misc/lkdtm/perms.c | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 5d41c2230d2e..c09133ac9803 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -143,7 +143,9 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(EXEC_VMALLOC), CRASHTYPE(EXEC_RODATA), CRASHTYPE(EXEC_USERSPACE), + CRASHTYPE(EXEC_NULL), CRASHTYPE(ACCESS_USERSPACE), + CRASHTYPE(ACCESS_NULL), CRASHTYPE(WRITE_RO), CRASHTYPE(WRITE_RO_AFTER_INIT), CRASHTYPE(WRITE_KERN), diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 3c6fd327e166..b69ee004a3f7 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -45,7 +45,9 @@ void lkdtm_EXEC_KMALLOC(void); void lkdtm_EXEC_VMALLOC(void); void lkdtm_EXEC_RODATA(void); void lkdtm_EXEC_USERSPACE(void); +void lkdtm_EXEC_NULL(void); void lkdtm_ACCESS_USERSPACE(void); +void lkdtm_ACCESS_NULL(void); /* lkdtm_refcount.c */ void lkdtm_REFCOUNT_INC_OVERFLOW(void); diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c index fa54add6375a..62f76d506f04 100644 --- a/drivers/misc/lkdtm/perms.c +++ b/drivers/misc/lkdtm/perms.c @@ -164,6 +164,11 @@ void lkdtm_EXEC_USERSPACE(void) vm_munmap(user_addr, PAGE_SIZE); } +void lkdtm_EXEC_NULL(void) +{ + execute_location(NULL, CODE_AS_IS); +} + void lkdtm_ACCESS_USERSPACE(void) { unsigned long user_addr, tmp = 0; @@ -195,6 +200,19 @@ void lkdtm_ACCESS_USERSPACE(void) vm_munmap(user_addr, PAGE_SIZE); } +void lkdtm_ACCESS_NULL(void) +{ + unsigned long tmp; + unsigned long *ptr = (unsigned long *)NULL; + + pr_info("attempting bad read at %px\n", ptr); + tmp = *ptr; + tmp += 0xc0dec0de; + + pr_info("attempting bad write at %px\n", ptr); + *ptr = tmp; +} + void __init lkdtm_perms_init(void) { /* Make sure we can write to __ro_after_init values during __init */ -- cgit v1.2.3 From 31cc9e09688c77b2e87e5770802ebb1fd8ac9011 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 20 Dec 2018 11:54:33 +0300 Subject: clk: clps711x: Remove board support Since board support for the CLPS711X platform was removed, remove the board support from the clk-clps711x driver. Signed-off-by: Alexander Shiyan Acked-by: Arnd Bergmann Signed-off-by: Stephen Boyd --- drivers/clk/clk-clps711x.c | 61 +++++++++------------------------------------- 1 file changed, 11 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index 2c04396402ab..c36c47bdba02 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -44,21 +44,21 @@ struct clps711x_clk { struct clk_hw_onecell_data clk_data; }; -static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, - u32 fref) +static void __init clps711x_clk_init_dt(struct device_node *np) { - u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi; + u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi, fref = 0; struct clps711x_clk *clps711x_clk; - unsigned i; + void __iomem *base; + + WARN_ON(of_property_read_u32(np, "startup-frequency", &fref)); - if (!base) - return ERR_PTR(-ENOMEM); + base = of_iomap(np, 0); + BUG_ON(!base); clps711x_clk = kzalloc(struct_size(clps711x_clk, clk_data.hws, CLPS711X_CLK_MAX), GFP_KERNEL); - if (!clps711x_clk) - return ERR_PTR(-ENOMEM); + BUG_ON(!clps711x_clk); spin_lock_init(&clps711x_clk->lock); @@ -137,52 +137,13 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, clk_hw_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); clps711x_clk->clk_data.hws[CLPS711X_CLK_TICK] = clk_hw_register_fixed_rate(NULL, "tick", NULL, 0, 64); - for (i = 0; i < CLPS711X_CLK_MAX; i++) - if (IS_ERR(clps711x_clk->clk_data.hws[i])) + for (tmp = 0; tmp < CLPS711X_CLK_MAX; tmp++) + if (IS_ERR(clps711x_clk->clk_data.hws[tmp])) pr_err("clk %i: register failed with %ld\n", - i, PTR_ERR(clps711x_clk->clk_data.hws[i])); - - return clps711x_clk; -} - -void __init clps711x_clk_init(void __iomem *base) -{ - struct clps711x_clk *clps711x_clk; - - clps711x_clk = _clps711x_clk_init(base, 73728000); - - BUG_ON(IS_ERR(clps711x_clk)); - - /* Clocksource */ - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1], - NULL, "clps711x-timer.0"); - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2], - NULL, "clps711x-timer.1"); - - /* Drivers */ - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM], - NULL, "clps711x-pwm"); - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART], - NULL, "clps711x-uart.0"); - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART], - NULL, "clps711x-uart.1"); -} - -#ifdef CONFIG_OF -static void __init clps711x_clk_init_dt(struct device_node *np) -{ - void __iomem *base = of_iomap(np, 0); - struct clps711x_clk *clps711x_clk; - u32 fref = 0; - - WARN_ON(of_property_read_u32(np, "startup-frequency", &fref)); - - clps711x_clk = _clps711x_clk_init(base, fref); - BUG_ON(IS_ERR(clps711x_clk)); + tmp, PTR_ERR(clps711x_clk->clk_data.hws[tmp])); clps711x_clk->clk_data.num = CLPS711X_CLK_MAX; of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clps711x_clk->clk_data); } CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt); -#endif -- cgit v1.2.3 From 309b32fb97d8cf0771373fb55e16b2852840c9aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 7 Jan 2019 20:49:37 +0100 Subject: pwm: Don't use memcmp() to compare state variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given that struct pwm_state is sparse (at least on some platforms), variables of this type might represent the same state because all fields are pairwise identical but still memcmp() returns a difference because some of the unused bits are different. To prevent surprises compare member by member instead of the whole occupied memory. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 1581f6ab1b1f..253a459fe0d8 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -472,7 +472,10 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) state->duty_cycle > state->period) return -EINVAL; - if (!memcmp(state, &pwm->state, sizeof(*state))) + if (state->period == pwm->state.period && + state->duty_cycle == pwm->state.duty_cycle && + state->polarity == pwm->state.polarity && + state->enabled == pwm->state.enabled) return 0; if (pwm->chip->ops->apply) { -- cgit v1.2.3 From cc2d22477779f189595db5c515bd5ef9c75a1f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 7 Jan 2019 20:49:39 +0100 Subject: pwm: Drop per-chip dbg_show callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This callback was introduced in commit 62099abf67a2 ("pwm: Add debugfs interface") in 2012 and up to now there is not a single user. So drop this unused code. Signed-off-by: Uwe Kleine-König [thierry.reding@gmail.com: remove kerneldoc for ->dbg_show()] Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 253a459fe0d8..3149204567f3 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -1036,10 +1036,7 @@ static int pwm_seq_show(struct seq_file *s, void *v) dev_name(chip->dev), chip->npwm, (chip->npwm != 1) ? "s" : ""); - if (chip->ops->dbg_show) - chip->ops->dbg_show(chip, s); - else - pwm_dbg_show(chip, s); + pwm_dbg_show(chip, s); return 0; } -- cgit v1.2.3 From 01482d2443db24aa5234f3ffa03b09f03c94f603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 7 Jan 2019 20:53:49 +0100 Subject: pwm: imx: Remove if block where the condition is always wrong MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ->remove() callback is only called when probe returned successfully. In this case the driver data cannot be NULL. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 55a3a363d5be..1e90d2b78625 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -444,8 +444,6 @@ static int imx_pwm_remove(struct platform_device *pdev) struct imx_chip *imx; imx = platform_get_drvdata(pdev); - if (imx == NULL) - return -ENODEV; imx_pwm_clk_disable_unprepare(&imx->chip); -- cgit v1.2.3 From f20b187e32e07914ff9878880c7d08ca89b5c3ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 7 Jan 2019 20:53:50 +0100 Subject: pwm: imx: Set driver data earlier simplifying the end of ->probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When ->probe() fails the driver core takes care of unsetting the driver data. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 1e90d2b78625..809493d86d22 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -390,7 +390,6 @@ static int imx_pwm_probe(struct platform_device *pdev) const struct imx_pwm_data *data; struct imx_chip *imx; struct resource *r; - int ret = 0; if (!of_id) return -ENODEV; @@ -401,6 +400,8 @@ static int imx_pwm_probe(struct platform_device *pdev) if (imx == NULL) return -ENOMEM; + platform_set_drvdata(pdev, imx); + imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(imx->clk_ipg)) { dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", @@ -431,12 +432,7 @@ static int imx_pwm_probe(struct platform_device *pdev) if (IS_ERR(imx->mmio_base)) return PTR_ERR(imx->mmio_base); - ret = pwmchip_add(&imx->chip); - if (ret < 0) - return ret; - - platform_set_drvdata(pdev, imx); - return 0; + return pwmchip_add(&imx->chip); } static int imx_pwm_remove(struct platform_device *pdev) -- cgit v1.2.3 From b9a5c60bc2f65561535dc05d0c740aa6e9e3bdf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 7 Jan 2019 20:53:51 +0100 Subject: pwm: imx: Don't print an error on -EPROBE_DEFER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When getting the peripheral clock fails with -EPROBE_DEFER the driver is usually probed again later and emitting an error message is irritating. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 809493d86d22..30380fcb5cfb 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -411,9 +411,14 @@ static int imx_pwm_probe(struct platform_device *pdev) imx->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(imx->clk_per)) { - dev_err(&pdev->dev, "getting per clock failed with %ld\n", - PTR_ERR(imx->clk_per)); - return PTR_ERR(imx->clk_per); + int ret = PTR_ERR(imx->clk_per); + + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "failed to get peripheral clock: %d\n", + ret); + + return ret; } imx->chip.ops = data->ops; -- cgit v1.2.3 From 4f0a0cd52d6c812fbf737e436b18f04eac2e312e Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Thu, 10 Jan 2019 11:14:07 +0100 Subject: spi: dw: fix warning unused variable 'ret' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_SPI_DESIGNWARE are enabled we see the unused variable warning in dw_spi_setup. ../drivers/spi/spi-dw.c: In function ‘dw_spi_setup’: ../drivers/spi/spi-dw.c:400:6: warning: unused variable ‘ret’ [-Wunused-variable] int ret; ^~~ Remove the unused varable. Fixes: 9400c41e77b8 ("spi: dw: Convert to use CS GPIO descriptors") Reported-by: Stephen Rothwell Signed-off-by: Anders Roxell Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index f54b498001a9..7092e58add2c 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -397,7 +397,6 @@ static int dw_spi_setup(struct spi_device *spi) { struct dw_spi_chip *chip_info = NULL; struct chip_data *chip; - int ret; /* Only alloc on first setup */ chip = spi_get_ctldata(spi); -- cgit v1.2.3 From 6375d40322f06925f5f24cd555b12567c830502b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 20 Dec 2018 11:55:22 +0800 Subject: brcmsmac: remove set but not used variables 'phybw40, maxtargetpwr' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c:1202:5: warning: variable 'phybw40' set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c:4625:5: warning: variable 'phybw40' set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c:4834:5: warning: variable 'phybw40' set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c:3085:17: warning: variable 'maxtargetpwr' set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c:4215:17: warning: variable 'maxtargetpwr' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- .../net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c index e78a93a45741..c6e107f41948 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1199,8 +1199,6 @@ wlc_lcnphy_rx_iq_est(struct brcms_phy *pi, { int wait_count = 0; bool result = true; - u8 phybw40; - phybw40 = CHSPEC_IS40(pi->radio_chanspec); mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5); @@ -3082,7 +3080,7 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) u8 bbmult; struct phytbl_info tab; s32 a1, b0, b1; - s32 tssi, pwr, maxtargetpwr, mintargetpwr; + s32 tssi, pwr, mintargetpwr; bool suspend; struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -3119,7 +3117,6 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) b0 = pi->txpa_2g[0]; b1 = pi->txpa_2g[1]; a1 = pi->txpa_2g[2]; - maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1); mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1); tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; @@ -4212,7 +4209,7 @@ static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi) s8 index; struct phytbl_info tab; s32 a1, b0, b1; - s32 tssi, pwr, maxtargetpwr, mintargetpwr; + s32 tssi, pwr, mintargetpwr; struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; pi->phy_lastcal = pi->sh->now; @@ -4249,7 +4246,6 @@ static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi) b0 = pi->txpa_2g[0]; b1 = pi->txpa_2g[1]; a1 = pi->txpa_2g[2]; - maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1); mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1); tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; @@ -4622,13 +4618,10 @@ static void wlc_lcnphy_radio_init(struct brcms_phy *pi) static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) { uint idx; - u8 phybw40; struct phytbl_info tab; const struct phytbl_info *tb; u32 val; - phybw40 = CHSPEC_IS40(pi->radio_chanspec); - for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]); @@ -4831,9 +4824,7 @@ static void wlc_lcnphy_baseband_init(struct brcms_phy *pi) void wlc_phy_init_lcnphy(struct brcms_phy *pi) { - u8 phybw40; struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; - phybw40 = CHSPEC_IS40(pi->radio_chanspec); pi_lcn->lcnphy_cal_counter = 0; pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense; -- cgit v1.2.3 From ba2ffc96321c8433606ceeb85c9e722b8113e5a7 Mon Sep 17 00:00:00 2001 From: Zumeng Chen Date: Wed, 19 Dec 2018 15:50:29 +0800 Subject: wlcore: Fix memory leak in case wl12xx_fetch_firmware failure Release fw_status, raw_fw_status, and tx_res_if when wl12xx_fetch_firmware failed instead of meaningless goto out to avoid the following memory leak reports(Only the last one listed): unreferenced object 0xc28a9a00 (size 512): comm "kworker/0:4", pid 31298, jiffies 2783204 (age 203.290s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<6624adab>] kmemleak_alloc+0x40/0x74 [<500ddb31>] kmem_cache_alloc_trace+0x1ac/0x270 [] wl12xx_chip_wakeup+0xc4/0x1fc [wlcore] [<76c5db53>] wl1271_op_add_interface+0x4a4/0x8f4 [wlcore] [] drv_add_interface+0xa4/0x1a0 [mac80211] [<65bac325>] ieee80211_reconfig+0x9c0/0x1644 [mac80211] [<2817c80e>] ieee80211_restart_work+0x90/0xc8 [mac80211] [<7e1d425a>] process_one_work+0x284/0x42c [<55f9432e>] worker_thread+0x2fc/0x48c [] kthread+0x148/0x160 [<63144b13>] ret_from_fork+0x14/0x2c [< (null)>] (null) [<1f6e7715>] 0xffffffff Signed-off-by: Zumeng Chen Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 26b187336875..2e12de813a5b 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1085,8 +1085,11 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) goto out; ret = wl12xx_fetch_firmware(wl, plt); - if (ret < 0) - goto out; + if (ret < 0) { + kfree(wl->fw_status); + kfree(wl->raw_fw_status); + kfree(wl->tx_res_if); + } out: return ret; -- cgit v1.2.3 From 72255c807156adeb167444c4206c9e5eece22287 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 20 Dec 2018 14:05:50 +0000 Subject: ray_cs: fix array out-of-bounds access Currently array element org[3] is being accessed, however the array is only 3 elements in size, so this looks like an off-by-one out-of-bounds error. Fix this by using org[2], which I believe was the original intent. This issue has existed in the driver back in the pre-git days, so no idea when it was introduced. Detected by CoverityScan, CID#711344 ("Out-of-bounds read") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ray_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 33ad87528d9a..8b2741c8edf2 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -959,7 +959,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) { /* This is the selective translation table, only 2 entries */ writeb(0xf8, - &((struct snaphdr_t __iomem *)ptx->var)->org[3]); + &((struct snaphdr_t __iomem *)ptx->var)->org[2]); } /* Copy body of ethernet packet without ethernet header */ memcpy_toio((void __iomem *)&ptx->var + -- cgit v1.2.3 From 4d95f99c59b8b814bcf09ba86020d937ec7caa86 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 20 Dec 2018 17:40:58 +0100 Subject: brcmfmac: Add DMI nvram filename quirk for PoV TAB-P1006W-232 tablet The Point of View TAB-P1006W-232 tablet contains quite generic names in the sys_vendor and product_name DMI strings, without this patch brcmfmac will try to load: brcmfmac43340-sdio.Insyde-BayTrail.txt as nvram file which is a bit too generic. Add a DMI quirk so that a unique and clearly identifiable nvram file name is used on the PoV TAB-P1006W-232 tablet. Signed-off-by: Hans de Goede Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c index 51d76ac45075..7535cb0d4ac0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c @@ -43,6 +43,10 @@ static const struct brcmf_dmi_data meegopad_t08_data = { BRCM_CC_43340_CHIP_ID, 2, "meegopad-t08" }; +static const struct brcmf_dmi_data pov_tab_p1006w_data = { + BRCM_CC_43340_CHIP_ID, 2, "pov-tab-p1006w-data" +}; + static const struct dmi_system_id dmi_platform_data[] = { { /* Match for the GPDwin which unfortunately uses somewhat @@ -81,6 +85,17 @@ static const struct dmi_system_id dmi_platform_data[] = { }, .driver_data = (void *)&meegopad_t08_data, }, + { + /* Point of View TAB-P1006W-232 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + .driver_data = (void *)&pov_tab_p1006w_data, + }, {} }; -- cgit v1.2.3 From 51c8d24101c79ffce3e79137e2cee5dfeb956dd7 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 22 Dec 2018 10:34:54 +0000 Subject: cw1200: fix missing unlock on error in cw1200_hw_scan() Add the missing unlock before return from function cw1200_hw_scan() in the error handling case. Fixes: 4f68ef64cd7f ("cw1200: Fix concurrency use-after-free bugs in cw1200_hw_scan()") Signed-off-by: Wei Yongjun Acked-by: Jia-Ju Bai Signed-off-by: Kalle Valo --- drivers/net/wireless/st/cw1200/scan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index 0a9eac93dd01..71e9b91cf15b 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -84,8 +84,11 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, req->ie_len); - if (!frame.skb) + if (!frame.skb) { + mutex_unlock(&priv->conf_mutex); + up(&priv->scan.lock); return -ENOMEM; + } if (req->ie_len) skb_put_data(frame.skb, req->ie, req->ie_len); -- cgit v1.2.3 From 06605b0d38b491c6dc52f4aee3e588e1309fbfaf Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Dec 2018 09:57:15 +0100 Subject: cw1200: drop useless LIST_HEAD Drop LIST_HEAD where the variable it declares has never been used. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier x; @@ - LIST_HEAD(x); ... when != x // Fixes: a910e4a94f692 ("cw1200: add driver for the ST-E CW1100 & CW1200 WLAN chipsets") Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/st/cw1200/queue.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c index 7c31b63b8258..7895efefa95d 100644 --- a/drivers/net/wireless/st/cw1200/queue.c +++ b/drivers/net/wireless/st/cw1200/queue.c @@ -283,7 +283,6 @@ int cw1200_queue_put(struct cw1200_queue *queue, struct cw1200_txpriv *txpriv) { int ret = 0; - LIST_HEAD(gc_list); struct cw1200_queue_stats *stats = queue->stats; if (txpriv->link_id >= queue->stats->map_capacity) -- cgit v1.2.3 From 42daad3343be4a4e1ee03e30a5f5cc731dadfef5 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Tue, 25 Dec 2018 19:22:24 -0600 Subject: brcmfmac: add a check for the status of usb_register usb_register() may fail, so let's check its status and issue an error message if it fails. Signed-off-by: Kangjie Lu Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index a4308c6e72d7..76cfaf6999c8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1550,6 +1550,10 @@ void brcmf_usb_exit(void) void brcmf_usb_register(void) { + int ret; + brcmf_dbg(USB, "Enter\n"); - usb_register(&brcmf_usbdrvr); + ret = usb_register(&brcmf_usbdrvr); + if (ret) + brcmf_err("usb_register failed %d\n", ret); } -- cgit v1.2.3 From 7fdcb8e1266093eb2ff1bc3ab430daf4775388ad Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Thu, 27 Dec 2018 14:56:18 +0530 Subject: rsi: add support for hardware scan offload With the current approach of scanning, roaming delays are observed. Firmware has support for back ground scanning. To get this advantage, mac80211 hardware scan is implemented, which decides type of scan to do based on connected state. When station is in not connected, driver returns with special value 1 to trigger software scan in mac80211. In case of connected state, background scan will be triggered. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 3 + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 67 ++++++++++++++ drivers/net/wireless/rsi/rsi_91x_main.c | 1 + drivers/net/wireless/rsi/rsi_91x_mgmt.c | 133 ++++++++++++++++++++++++++++ drivers/net/wireless/rsi/rsi_main.h | 22 +++++ drivers/net/wireless/rsi/rsi_mgmt.h | 35 ++++++++ 6 files changed, 261 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 182b06629371..1dbaab2a96b7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -100,6 +100,9 @@ int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) mgmt_desc->frame_type = TX_DOT11_MGMT; mgmt_desc->header_len = MIN_802_11_HDR_LEN; mgmt_desc->xtend_desc_size = header_size - FRAME_DESC_SZ; + + if (ieee80211_is_probe_req(wh->frame_control)) + mgmt_desc->frame_info = cpu_to_le16(RSI_INSERT_SEQ_IN_FW); mgmt_desc->frame_info |= cpu_to_le16(RATE_INFO_ENABLE); if (is_broadcast_ether_addr(wh->addr1)) mgmt_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT); diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index e56fc83faf0e..aded1ae4fad5 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -229,6 +229,68 @@ static void rsi_register_rates_channels(struct rsi_hw *adapter, int band) /* sbands->ht_cap.mcs.rx_highest = 0x82; */ } +static int rsi_mac80211_hw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req) +{ + struct cfg80211_scan_request *scan_req = &hw_req->req; + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + struct ieee80211_bss_conf *bss = &vif->bss_conf; + + rsi_dbg(INFO_ZONE, "***** Hardware scan start *****\n"); + + if (common->fsm_state != FSM_MAC_INIT_DONE) + return -ENODEV; + + if ((common->wow_flags & RSI_WOW_ENABLED) || + scan_req->n_channels == 0) + return -EINVAL; + + /* Scan already in progress. So return */ + if (common->bgscan_en) + return -EBUSY; + + /* If STA is not connected, return with special value 1, in order + * to start sw_scan in mac80211 + */ + if (!bss->assoc) + return 1; + + mutex_lock(&common->mutex); + common->hwscan = scan_req; + if (!rsi_send_bgscan_params(common, RSI_START_BGSCAN)) { + if (!rsi_send_bgscan_probe_req(common, vif)) { + rsi_dbg(INFO_ZONE, "Background scan started...\n"); + common->bgscan_en = true; + } + } + mutex_unlock(&common->mutex); + + return 0; +} + +static void rsi_mac80211_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + struct cfg80211_scan_info info; + + rsi_dbg(INFO_ZONE, "***** Hardware scan stop *****\n"); + mutex_lock(&common->mutex); + + if (common->bgscan_en) { + if (!rsi_send_bgscan_params(common, RSI_STOP_BGSCAN)) + common->bgscan_en = false; + info.aborted = false; + ieee80211_scan_completed(adapter->hw, &info); + rsi_dbg(INFO_ZONE, "Back ground scan cancelled\b\n"); + } + common->hwscan = NULL; + mutex_unlock(&common->mutex); +} + /** * rsi_mac80211_detach() - This function is used to de-initialize the * Mac80211 stack. @@ -1917,6 +1979,8 @@ static const struct ieee80211_ops mac80211_ops = { .suspend = rsi_mac80211_suspend, .resume = rsi_mac80211_resume, #endif + .hw_scan = rsi_mac80211_hw_scan_start, + .cancel_hw_scan = rsi_mac80211_cancel_hw_scan, }; /** @@ -1999,6 +2063,9 @@ int rsi_mac80211_attach(struct rsi_common *common) common->max_stations = wiphy->max_ap_assoc_sta; rsi_dbg(ERR_ZONE, "Max Stations Allowed = %d\n", common->max_stations); hw->sta_data_size = sizeof(struct rsi_sta); + + wiphy->max_scan_ssids = RSI_MAX_SCAN_SSIDS; + wiphy->max_scan_ie_len = RSI_MAX_SCAN_IE_LEN; wiphy->flags = WIPHY_FLAG_REPORTS_OBSS; wiphy->flags |= WIPHY_FLAG_AP_UAPSD; wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 01d99ed985ee..ca3a55ed72e4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -328,6 +328,7 @@ struct rsi_hw *rsi_91x_init(u16 oper_mode) } rsi_default_ps_params(adapter); + init_bgscan_params(common); spin_lock_init(&adapter->ps_lock); timer_setup(&common->roc_timer, rsi_roc_timeout, 0); init_completion(&common->wlan_init_completion); diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 1095df7d9573..404241424a62 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -15,6 +15,7 @@ */ #include +#include #include "rsi_mgmt.h" #include "rsi_common.h" #include "rsi_ps.h" @@ -236,6 +237,18 @@ static void rsi_set_default_parameters(struct rsi_common *common) common->dtim_cnt = RSI_DTIM_COUNT; } +void init_bgscan_params(struct rsi_common *common) +{ + memset((u8 *)&common->bgscan, 0, sizeof(struct rsi_bgscan_params)); + common->bgscan.bgscan_threshold = RSI_DEF_BGSCAN_THRLD; + common->bgscan.roam_threshold = RSI_DEF_ROAM_THRLD; + common->bgscan.bgscan_periodicity = RSI_BGSCAN_PERIODICITY; + common->bgscan.num_bgscan_channels = 0; + common->bgscan.two_probe = 1; + common->bgscan.active_scan_duration = RSI_ACTIVE_SCAN_TIME; + common->bgscan.passive_scan_duration = RSI_PASSIVE_SCAN_TIME; +} + /** * rsi_set_contention_vals() - This function sets the contention values for the * backoff procedure. @@ -1628,6 +1641,107 @@ int rsi_send_wowlan_request(struct rsi_common *common, u16 flags, } #endif +int rsi_send_bgscan_params(struct rsi_common *common, int enable) +{ + struct rsi_bgscan_params *params = &common->bgscan; + struct cfg80211_scan_request *scan_req = common->hwscan; + struct rsi_bgscan_config *bgscan; + struct sk_buff *skb; + u16 frame_len = sizeof(*bgscan); + u8 i; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending bgscan params frame\n", __func__); + + skb = dev_alloc_skb(frame_len); + if (!skb) + return -ENOMEM; + memset(skb->data, 0, frame_len); + + bgscan = (struct rsi_bgscan_config *)skb->data; + rsi_set_len_qno(&bgscan->desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); + bgscan->desc_dword0.frame_type = BG_SCAN_PARAMS; + bgscan->bgscan_threshold = cpu_to_le16(params->bgscan_threshold); + bgscan->roam_threshold = cpu_to_le16(params->roam_threshold); + if (enable) + bgscan->bgscan_periodicity = + cpu_to_le16(params->bgscan_periodicity); + bgscan->active_scan_duration = + cpu_to_le16(params->active_scan_duration); + bgscan->passive_scan_duration = + cpu_to_le16(params->passive_scan_duration); + bgscan->two_probe = params->two_probe; + + bgscan->num_bgscan_channels = scan_req->n_channels; + for (i = 0; i < bgscan->num_bgscan_channels; i++) + bgscan->channels2scan[i] = + cpu_to_le16(scan_req->channels[i]->hw_value); + + skb_put(skb, frame_len); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/* This function sends the probe request to be used by firmware in + * background scan + */ +int rsi_send_bgscan_probe_req(struct rsi_common *common, + struct ieee80211_vif *vif) +{ + struct cfg80211_scan_request *scan_req = common->hwscan; + struct rsi_bgscan_probe *bgscan; + struct sk_buff *skb; + struct sk_buff *probereq_skb; + u16 frame_len = sizeof(*bgscan); + size_t ssid_len = 0; + u8 *ssid = NULL; + + rsi_dbg(MGMT_TX_ZONE, + "%s: Sending bgscan probe req frame\n", __func__); + + if (common->priv->sc_nvifs <= 0) + return -ENODEV; + + if (scan_req->n_ssids) { + ssid = scan_req->ssids[0].ssid; + ssid_len = scan_req->ssids[0].ssid_len; + } + + skb = dev_alloc_skb(frame_len + MAX_BGSCAN_PROBE_REQ_LEN); + if (!skb) + return -ENOMEM; + memset(skb->data, 0, frame_len + MAX_BGSCAN_PROBE_REQ_LEN); + + bgscan = (struct rsi_bgscan_probe *)skb->data; + bgscan->desc_dword0.frame_type = BG_SCAN_PROBE_REQ; + bgscan->flags = cpu_to_le16(HOST_BG_SCAN_TRIG); + if (common->band == NL80211_BAND_5GHZ) { + bgscan->mgmt_rate = cpu_to_le16(RSI_RATE_6); + bgscan->def_chan = cpu_to_le16(40); + } else { + bgscan->mgmt_rate = cpu_to_le16(RSI_RATE_1); + bgscan->def_chan = cpu_to_le16(11); + } + bgscan->channel_scan_time = cpu_to_le16(RSI_CHANNEL_SCAN_TIME); + + probereq_skb = ieee80211_probereq_get(common->priv->hw, vif->addr, ssid, + ssid_len, scan_req->ie_len); + + memcpy(&skb->data[frame_len], probereq_skb->data, probereq_skb->len); + + bgscan->probe_req_length = cpu_to_le16(probereq_skb->len); + + rsi_set_len_qno(&bgscan->desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ + probereq_skb->len), + RSI_WIFI_MGMT_Q); + + skb_put(skb, frame_len + probereq_skb->len); + + dev_kfree_skb(probereq_skb); + + return rsi_send_internal_mgmt_frame(common, skb); +} + /** * rsi_handle_ta_confirm_type() - This function handles the confirm frames. * @common: Pointer to the driver private structure. @@ -1771,9 +1885,28 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common, return 0; } break; + + case SCAN_REQUEST: + rsi_dbg(INFO_ZONE, "Set channel confirm\n"); + break; + case WAKEUP_SLEEP_REQUEST: rsi_dbg(INFO_ZONE, "Wakeup/Sleep confirmation.\n"); return rsi_handle_ps_confirm(adapter, msg); + + case BG_SCAN_PROBE_REQ: + rsi_dbg(INFO_ZONE, "BG scan complete event\n"); + if (common->bgscan_en) { + struct cfg80211_scan_info info; + + if (!rsi_send_bgscan_params(common, RSI_STOP_BGSCAN)) + common->bgscan_en = 0; + info.aborted = false; + ieee80211_scan_completed(adapter->hw, &info); + } + rsi_dbg(INFO_ZONE, "Background scan completed\n"); + break; + default: rsi_dbg(INFO_ZONE, "%s: Invalid TA confirm pkt received\n", __func__); diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index a084f224bb03..4dc0c0123469 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -164,6 +164,24 @@ struct transmit_q_stats { u32 total_tx_pkt_freed[NUM_EDCA_QUEUES + 2]; }; +#define MAX_BGSCAN_CHANNELS_DUAL_BAND 38 +#define MAX_BGSCAN_PROBE_REQ_LEN 0x64 +#define RSI_DEF_BGSCAN_THRLD 0x0 +#define RSI_DEF_ROAM_THRLD 0xa +#define RSI_BGSCAN_PERIODICITY 0x1e +#define RSI_ACTIVE_SCAN_TIME 0x14 +#define RSI_PASSIVE_SCAN_TIME 0x46 +#define RSI_CHANNEL_SCAN_TIME 20 +struct rsi_bgscan_params { + u16 bgscan_threshold; + u16 roam_threshold; + u16 bgscan_periodicity; + u8 num_bgscan_channels; + u8 two_probe; + u16 active_scan_duration; + u16 passive_scan_duration; +}; + struct vif_priv { bool is_ht; bool sgi; @@ -289,6 +307,10 @@ struct rsi_common { bool eapol4_confirm; void *bt_adapter; + + struct cfg80211_scan_request *hwscan; + struct rsi_bgscan_params bgscan; + u8 bgscan_en; }; struct eepromrw_info { diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 359fbdf85739..ea83faa15c7e 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -228,6 +228,9 @@ #define RSI_MAX_TX_AGGR_FRMS 8 #define RSI_MAX_RX_AGGR_FRMS 8 +#define RSI_MAX_SCAN_SSIDS 16 +#define RSI_MAX_SCAN_IE_LEN 256 + enum opmode { RSI_OPMODE_UNSUPPORTED = -1, RSI_OPMODE_AP = 0, @@ -623,6 +626,34 @@ struct rsi_wowlan_req { u16 host_sleep_status; } __packed; +#define RSI_START_BGSCAN 1 +#define RSI_STOP_BGSCAN 0 +#define HOST_BG_SCAN_TRIG BIT(4) +struct rsi_bgscan_config { + struct rsi_cmd_desc_dword0 desc_dword0; + __le64 reserved; + __le32 reserved1; + __le16 bgscan_threshold; + __le16 roam_threshold; + __le16 bgscan_periodicity; + u8 num_bgscan_channels; + u8 two_probe; + __le16 active_scan_duration; + __le16 passive_scan_duration; + __le16 channels2scan[MAX_BGSCAN_CHANNELS_DUAL_BAND]; +} __packed; + +struct rsi_bgscan_probe { + struct rsi_cmd_desc_dword0 desc_dword0; + __le64 reserved; + __le32 reserved1; + __le16 mgmt_rate; + __le16 flags; + __le16 def_chan; + __le16 channel_scan_time; + __le16 probe_req_length; +} __packed; + static inline u32 rsi_get_queueno(u8 *addr, u16 offset) { return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12; @@ -694,4 +725,8 @@ int rsi_send_wowlan_request(struct rsi_common *common, u16 flags, #endif int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, struct ieee80211_vif *vif); +void init_bgscan_params(struct rsi_common *common); +int rsi_send_bgscan_params(struct rsi_common *common, int enable); +int rsi_send_bgscan_probe_req(struct rsi_common *common, + struct ieee80211_vif *vif); #endif -- cgit v1.2.3 From 5a1c18b761ddb299a06746948b9ec2814b04fa92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 2 Jan 2019 00:00:01 +0100 Subject: bcma: keep a direct pointer to the struct device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accessing struct device is pretty useful/common so having a direct pointer: 1) Simplifies some code 2) Makes bcma_bus_get_host_dev() unneeded 3) Allows further improvements like using dev_* printing helpers Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/bcma/bcma_private.h | 1 - drivers/bcma/driver_gpio.c | 2 +- drivers/bcma/host_pci.c | 2 ++ drivers/bcma/host_soc.c | 4 ++-- drivers/bcma/main.c | 45 ++++++++++----------------------------------- 5 files changed, 15 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index a4aac370f21f..1f0e66310b23 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -33,7 +33,6 @@ int __init bcma_bus_early_register(struct bcma_bus *bus); int bcma_bus_suspend(struct bcma_bus *bus); int bcma_bus_resume(struct bcma_bus *bus); #endif -struct device *bcma_bus_get_host_dev(struct bcma_bus *bus); /* scan.c */ void bcma_detect_chip(struct bcma_bus *bus); diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index 2c0ffb77d738..a5df3d111334 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c @@ -183,7 +183,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) chip->direction_input = bcma_gpio_direction_input; chip->direction_output = bcma_gpio_direction_output; chip->owner = THIS_MODULE; - chip->parent = bcma_bus_get_host_dev(bus); + chip->parent = bus->dev; #if IS_BUILTIN(CONFIG_OF) chip->of_node = cc->core->dev.of_node; #endif diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 63410ecfe640..f52239feb4cb 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -196,6 +196,8 @@ static int bcma_host_pci_probe(struct pci_dev *dev, goto err_pci_release_regions; } + bus->dev = &dev->dev; + /* Map MMIO */ err = -ENOMEM; bus->mmio = pci_iomap(dev, 0, ~0UL); diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c index 2dce34789329..c8073b509a2b 100644 --- a/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c @@ -179,7 +179,6 @@ int __init bcma_host_soc_register(struct bcma_soc *soc) /* Host specific */ bus->hosttype = BCMA_HOSTTYPE_SOC; bus->ops = &bcma_host_soc_ops; - bus->host_pdev = NULL; /* Initialize struct, detect chip */ bcma_init_bus(bus); @@ -213,6 +212,8 @@ static int bcma_host_soc_probe(struct platform_device *pdev) if (!bus) return -ENOMEM; + bus->dev = dev; + /* Map MMIO */ bus->mmio = of_iomap(np, 0); if (!bus->mmio) @@ -221,7 +222,6 @@ static int bcma_host_soc_probe(struct platform_device *pdev) /* Host specific */ bus->hosttype = BCMA_HOSTTYPE_SOC; bus->ops = &bcma_host_soc_ops; - bus->host_pdev = pdev; /* Initialize struct, detect chip */ bcma_init_bus(bus); diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index fc1f4acdd189..6535614a7dc1 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -223,8 +223,8 @@ unsigned int bcma_core_irq(struct bcma_device *core, int num) mips_irq = bcma_core_mips_irq(core); return mips_irq <= 4 ? mips_irq + 2 : 0; } - if (bus->host_pdev) - return bcma_of_get_irq(&bus->host_pdev->dev, core, num); + if (bus->dev) + return bcma_of_get_irq(bus->dev, core, num); return 0; case BCMA_HOSTTYPE_SDIO: return 0; @@ -239,18 +239,18 @@ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) core->dev.release = bcma_release_core_dev; core->dev.bus = &bcma_bus_type; dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); - core->dev.parent = bcma_bus_get_host_dev(bus); - if (core->dev.parent) - bcma_of_fill_device(core->dev.parent, core); + core->dev.parent = bus->dev; + if (bus->dev) + bcma_of_fill_device(bus->dev, core); switch (bus->hosttype) { case BCMA_HOSTTYPE_PCI: - core->dma_dev = &bus->host_pci->dev; + core->dma_dev = bus->dev; core->irq = bus->host_pci->irq; break; case BCMA_HOSTTYPE_SOC: - if (IS_ENABLED(CONFIG_OF) && bus->host_pdev) { - core->dma_dev = &bus->host_pdev->dev; + if (IS_ENABLED(CONFIG_OF) && bus->dev) { + core->dma_dev = bus->dev; } else { core->dev.dma_mask = &core->dev.coherent_dma_mask; core->dma_dev = &core->dev; @@ -261,28 +261,6 @@ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) } } -struct device *bcma_bus_get_host_dev(struct bcma_bus *bus) -{ - switch (bus->hosttype) { - case BCMA_HOSTTYPE_PCI: - if (bus->host_pci) - return &bus->host_pci->dev; - else - return NULL; - case BCMA_HOSTTYPE_SOC: - if (bus->host_pdev) - return &bus->host_pdev->dev; - else - return NULL; - case BCMA_HOSTTYPE_SDIO: - if (bus->host_sdio) - return &bus->host_sdio->dev; - else - return NULL; - } - return NULL; -} - void bcma_init_bus(struct bcma_bus *bus) { mutex_lock(&bcma_buses_mutex); @@ -402,7 +380,6 @@ int bcma_bus_register(struct bcma_bus *bus) { int err; struct bcma_device *core; - struct device *dev; /* Scan for devices (cores) */ err = bcma_bus_scan(bus); @@ -425,10 +402,8 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_early_init(&bus->drv_pci[0]); } - dev = bcma_bus_get_host_dev(bus); - if (dev) { - of_platform_default_populate(dev->of_node, NULL, dev); - } + if (bus->dev) + of_platform_default_populate(bus->dev->of_node, NULL, bus->dev); /* Cores providing flash access go before SPROM init */ list_for_each_entry(core, &bus->cores, list) { -- cgit v1.2.3 From 777bc4801a6868fcbff09ffb6e30f023e7c5ed38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 2 Jan 2019 00:00:02 +0100 Subject: bcma: use dev_* printing functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It provides more meaningful messages. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/bcma/bcma_private.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 1f0e66310b23..6eded32d1aac 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -10,13 +10,13 @@ #include #define bcma_err(bus, fmt, ...) \ - pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) + dev_err((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__) #define bcma_warn(bus, fmt, ...) \ - pr_warn("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) + dev_warn((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__) #define bcma_info(bus, fmt, ...) \ - pr_info("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) + dev_info((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__) #define bcma_debug(bus, fmt, ...) \ - pr_debug("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) + dev_dbg((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__) struct bcma_bus; -- cgit v1.2.3 From 3a33bd840523aaa06f4429fbfd38922bf0dc2e8d Mon Sep 17 00:00:00 2001 From: Lo-Hsiang Lo Date: Mon, 7 Jan 2019 08:46:16 +0000 Subject: brcmfmac: fix system warning message during wowl suspend There is a system warning message, warn_slowpath-fmt, during suspend while using supplicant join AP and enable wowl feature by IW command. It's caused by brcmf_pno_remove_request path can't find the reqid. This fix will not go to remove pno request function if there is no pno scan. Acked-by: Arend van Spriel Signed-off-by: Lo-Hsiang Lo Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index ffa243e2e2d0..37b403877228 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -496,6 +496,11 @@ int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid) brcmf_dbg(TRACE, "reqid=%llu\n", reqid); pi = ifp_to_pno(ifp); + + /* No PNO request */ + if (!pi->n_reqs) + return 0; + err = brcmf_pno_remove_request(pi, reqid); if (err) return err; -- cgit v1.2.3 From 4ad0be160544ffbdafb7cec39bb8e6dd0a97317a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 Jan 2019 14:33:27 +0100 Subject: brcmfmac: Use firmware_request_nowarn for the clm_blob The linux-firmware brcmfmac firmware files contain an embedded table with per country allowed channels and strength info. For recent hardware these versions of the firmware are specially build for linux-firmware, the firmware files directly available from Cypress rely on a separate clm_blob file for this info. For some unknown reason Cypress refuses to provide the standard firmware files + clm_blob files it uses elsewhere for inclusion into linux-firmware, instead relying on these special builds with the clm_blob info embedded. This means that the linux-firmware firmware versions often lag behind, but I digress. The brcmfmac driver does support the separate clm_blob file and always tries to load this. Currently we use request_firmware for this. This means that on any standard install, using the standard combo of linux-kernel + linux-firmware, we will get a warning: "Direct firmware load for ... failed with error -2" On top of this, brcmfmac itself prints: "no clm_blob available (err=-2), device may have limited channels available". This commit switches to firmware_request_nowarn, fixing almost any brcmfmac device logging the warning (it leaves the brcmfmac info message in place). Signed-off-by: Hans de Goede Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 1f1e95a15a17..0ce1d8174e6d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -149,7 +149,7 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) return err; } - err = request_firmware(&clm, clm_name, bus->dev); + err = firmware_request_nowarn(&clm, clm_name, bus->dev); if (err) { brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", err); -- cgit v1.2.3 From 74fa750e63a9b962583213d161a79991188c6ec8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Jan 2019 12:48:42 +0100 Subject: spi: davinci: Get rid of dangling variable The previous commit left a variable unused, my bad. Clean it up. Cc: Stephen Rothwell Cc: David Lechner Reported-by: Stephen Rothwell Fixes: 101a68e74fe0 ("spi: davinci: Convert to use CS GPIO descriptors") Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 5870afe3845b..eb246ebcfa3a 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -423,7 +423,6 @@ static int davinci_spi_of_setup(struct spi_device *spi) static int davinci_spi_setup(struct spi_device *spi) { struct davinci_spi *dspi; - struct spi_master *master = spi->master; struct device_node *np = spi->dev.of_node; bool internal_cs = true; -- cgit v1.2.3 From 0ab66b3c326ef8f77dae9f528118966365757c0c Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Thu, 10 Jan 2019 12:11:16 +0800 Subject: regulator: max77620: Initialize values for DT properties If regulator DT node doesn't exist, its of_parse_cb callback function isn't called. Then all values for DT properties are filled with zero. This leads to wrong register update for FPS and POK settings. Signed-off-by: Jinyoung Park Signed-off-by: Mark Zhang Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/regulator/max77620-regulator.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index b94e3a721721..cd93cf53e23c 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -1,7 +1,7 @@ /* * Maxim MAX77620 Regulator driver * - * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. * * Author: Mallikarjun Kasoju * Laxman Dewangan @@ -803,6 +803,14 @@ static int max77620_regulator_probe(struct platform_device *pdev) rdesc = &rinfo[id].desc; pmic->rinfo[id] = &max77620_regs_info[id]; pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; + pmic->reg_pdata[id].active_fps_src = -1; + pmic->reg_pdata[id].active_fps_pd_slot = -1; + pmic->reg_pdata[id].active_fps_pu_slot = -1; + pmic->reg_pdata[id].suspend_fps_src = -1; + pmic->reg_pdata[id].suspend_fps_pd_slot = -1; + pmic->reg_pdata[id].suspend_fps_pu_slot = -1; + pmic->reg_pdata[id].power_ok = -1; + pmic->reg_pdata[id].ramp_rate_setting = -1; ret = max77620_read_slew_rate(pmic, id); if (ret < 0) -- cgit v1.2.3 From ce938231bd3b1d7af3cbd8836f084801090470e1 Mon Sep 17 00:00:00 2001 From: "Daniel F. Dickinson" Date: Sat, 22 Dec 2018 01:09:13 -0500 Subject: ath9k: Avoid OF no-EEPROM quirks without qca,no-eeprom ath9k_of_init() function[0] was initially written on the assumption that if someone had an explicit ath9k OF node that "there must be something wrong, why would someone add an OF node if everything is fine"[1] (Quoting Martin Blumenstingl ) "it turns out it's not that simple. with your requirements I'm now aware of two use-cases where the current code in ath9k_of_init() doesn't work without modifications"[1] The "your requirements" Martin speaks of is the result of the fact that I have a device (PowerCloud Systems CR5000) has some kind of default - not unique mac address - set and requires to set the correct MAC address via mac-address devicetree property, however: "some cards come with a physical EEPROM chip [or OTP] so "qca,no-eeprom" should not be set (your use-case). in this case AH_USE_EEPROM should be set (which is the default when there is no OF node)"[1] The other use case is: the firmware on some PowerMac G5 seems to add a OF node for the ath9k card automatically. depending on the EEPROM on the card AH_NO_EEP_SWAP should be unset (which is the default when there is no OF node). see [3] After this patch to ath9k_of_init() the new behavior will be: if there's no OF node then everything is the same as before if there's an empty OF node then ath9k will use the hardware EEPROM (before ath9k would fail to initialize because no EEPROM data was provided by userspace) if there's an OF node with only a MAC address then ath9k will use the MAC address and the hardware EEPROM (see the case above) with "qca,no-eeprom" EEPROM data from userspace will be requested. the behavior here will not change [1] Martin provides additional background on EEPROM swapping[1]. Thanks to Christian Lamparter for all his help on troubleshooting this issue and the basis for this patch. [0]https://elixir.bootlin.com/linux/v4.20-rc7/source/drivers/net/wireless/ath/ath9k/init.c#L615 [1]https://github.com/openwrt/openwrt/pull/1645#issuecomment-448027058 [2]https://github.com/openwrt/openwrt/pull/1613 [3]https://patchwork.kernel.org/patch/10241731/ Fixes: 138b41253d9c ("ath9k: parse the device configuration from an OF node") Reviewed-by: Martin Blumenstingl Tested-by: Martin Blumenstingl Signed-off-by: Daniel F. Dickinson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index c070a9e51ebf..fae572b38416 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -636,15 +636,15 @@ static int ath9k_of_init(struct ath_softc *sc) ret = ath9k_eeprom_request(sc, eeprom_name); if (ret) return ret; + + ah->ah_flags &= ~AH_USE_EEPROM; + ah->ah_flags |= AH_NO_EEP_SWAP; } mac = of_get_mac_address(np); if (mac) ether_addr_copy(common->macaddr, mac); - ah->ah_flags &= ~AH_USE_EEPROM; - ah->ah_flags |= AH_NO_EEP_SWAP; - return 0; } -- cgit v1.2.3 From fc6a6521556c8250e356ddc6a3f2391aa62dc976 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Wed, 26 Dec 2018 00:43:28 -0600 Subject: ath6kl: return error code in ath6kl_wmi_set_roam_lrssi_cmd() ath6kl_wmi_cmd_send could fail, so let's return its error code upstream. Signed-off-by: Kangjie Lu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 9d7ac1ab2d02..68854c45d0a4 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -776,10 +776,8 @@ int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi) cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR; cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS; - ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID, + return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID, NO_SYNC_WMIFLAG); - - return 0; } int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid) -- cgit v1.2.3 From e8dacf5957ea583c2a1f48600043a6f76e340d1e Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Thu, 10 Jan 2019 14:26:21 +0200 Subject: gpio: mvebu: implement get_direction struct gpio_chip documentation recommends to always implement this callback function. A more concrete motivation is to be able (in combination with GPIOD_ASIS) to detect whether the bootloader has changed the state of a GPIO signal. Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7d5c55494ccd..f97ed32b8beb 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -376,6 +376,16 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, return 0; } +static int mvebu_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) +{ + struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); + u32 u; + + regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u); + + return !!(u & BIT(pin)); +} + static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); @@ -1130,6 +1140,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.parent = &pdev->dev; mvchip->chip.request = gpiochip_generic_request; mvchip->chip.free = gpiochip_generic_free; + mvchip->chip.get_direction = mvebu_gpio_get_direction; mvchip->chip.direction_input = mvebu_gpio_direction_input; mvchip->chip.get = mvebu_gpio_get; mvchip->chip.direction_output = mvebu_gpio_direction_output; -- cgit v1.2.3 From 72893f0c6bd399ce84e3c1c9fc69d234fe37d098 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 31 Dec 2018 21:55:21 +0100 Subject: gpiolib-acpi: Preserve non direction flags when updating gpiod_flags __acpi_gpio_update_gpiod_flags purpose is to make the gpiod_flags used when requesting a GPIO match the restrictions from the ACPI resource, as stored in acpi_gpio_info.flags. But acpi_gpio_info.flags only contains direction info, and the requester may have passed in special non-direction flags like GPIOD_FLAGS_BIT_NONEXCLUSIVE, which we currently clobber. This commit modifies __acpi_gpio_update_gpiod_flags to preserve these special flags, so that a requested of an ACPI GPIO can e.g. pass GPIOD_FLAGS_BIT_NONEXCLUSIV and have it work as intended. Acked-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 48534bda73d3..f0763e0e02f1 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -474,6 +474,9 @@ acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio) static int __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) { + const enum gpiod_flags mask = + GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT | + GPIOD_FLAGS_BIT_DIR_VAL; int ret = 0; /* @@ -494,7 +497,7 @@ __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) if (((*flags & GPIOD_FLAGS_BIT_DIR_SET) && (diff & GPIOD_FLAGS_BIT_DIR_OUT)) || ((*flags & GPIOD_FLAGS_BIT_DIR_OUT) && (diff & GPIOD_FLAGS_BIT_DIR_VAL))) ret = -EINVAL; - *flags = update; + *flags = (*flags & ~mask) | (update & mask); } return ret; } -- cgit v1.2.3 From 1d67a232105b4dec2b10b2689f9cb89cc366d62f Mon Sep 17 00:00:00 2001 From: Dianlong Li Date: Thu, 13 Dec 2018 18:13:50 +0800 Subject: rtc: sd3078: new driver. The sd3078 is a combination RTC and SRAM device with I2C interface. Signed-off-by: Dianlong Li Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 9 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-sd3078.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 drivers/rtc/rtc-sd3078.c (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 225b0b8516f3..a24fe8b7b98a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -646,6 +646,15 @@ config RTC_DRV_S5M This driver can also be built as a module. If so, the module will be called rtc-s5m. +config RTC_DRV_SD3078 + tristate "ZXW Crystal SD3078" + help + If you say yes here you get support for the ZXW Crystal + SD3078 RTC chips. + + This driver can also be built as a module. If so, the module + will be called rtc-sd3078 + endif # I2C comment "SPI RTC drivers" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index df022d820bee..39eb6de4ad74 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -149,6 +149,7 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o +obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o diff --git a/drivers/rtc/rtc-sd3078.c b/drivers/rtc/rtc-sd3078.c new file mode 100644 index 000000000000..a70d7311d039 --- /dev/null +++ b/drivers/rtc/rtc-sd3078.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Real Time Clock (RTC) Driver for sd3078 + * Copyright (C) 2018 Zoro Li + */ + +#include +#include +#include +#include +#include +#include + +#define SD3078_REG_SC 0x00 +#define SD3078_REG_MN 0x01 +#define SD3078_REG_HR 0x02 +#define SD3078_REG_DW 0x03 +#define SD3078_REG_DM 0x04 +#define SD3078_REG_MO 0x05 +#define SD3078_REG_YR 0x06 + +#define SD3078_REG_CTRL1 0x0f +#define SD3078_REG_CTRL2 0x10 +#define SD3078_REG_CTRL3 0x11 + +#define KEY_WRITE1 0x80 +#define KEY_WRITE2 0x04 +#define KEY_WRITE3 0x80 + +#define NUM_TIME_REGS (SD3078_REG_YR - SD3078_REG_SC + 1) + +/* + * The sd3078 has write protection + * and we can choose whether or not to use it. + * Write protection is turned off by default. + */ +#define WRITE_PROTECT_EN 0 + +struct sd3078 { + struct rtc_device *rtc; + struct regmap *regmap; +}; + +/* + * In order to prevent arbitrary modification of the time register, + * when modification of the register, + * the "write" bit needs to be written in a certain order. + * 1. set WRITE1 bit + * 2. set WRITE2 bit + * 3. set WRITE3 bit + */ +static void sd3078_enable_reg_write(struct sd3078 *sd3078) +{ + regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2, + KEY_WRITE1, KEY_WRITE1); + regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1, + KEY_WRITE2, KEY_WRITE2); + regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1, + KEY_WRITE3, KEY_WRITE3); +} + +#if WRITE_PROTECT_EN +/* + * In order to prevent arbitrary modification of the time register, + * we should disable the write function. + * when disable write, + * the "write" bit needs to be clear in a certain order. + * 1. clear WRITE2 bit + * 2. clear WRITE3 bit + * 3. clear WRITE1 bit + */ +static void sd3078_disable_reg_write(struct sd3078 *sd3078) +{ + regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1, + KEY_WRITE2, 0); + regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1, + KEY_WRITE3, 0); + regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2, + KEY_WRITE1, 0); +} +#endif + +static int sd3078_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char hour; + unsigned char rtc_data[NUM_TIME_REGS] = {0}; + struct i2c_client *client = to_i2c_client(dev); + struct sd3078 *sd3078 = i2c_get_clientdata(client); + int ret; + + ret = regmap_bulk_read(sd3078->regmap, SD3078_REG_SC, rtc_data, + NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "reading from RTC failed with err:%d\n", ret); + return ret; + } + + tm->tm_sec = bcd2bin(rtc_data[SD3078_REG_SC] & 0x7F); + tm->tm_min = bcd2bin(rtc_data[SD3078_REG_MN] & 0x7F); + + /* + * The sd3078 supports 12/24 hour mode. + * When getting time, + * we need to convert the 12 hour mode to the 24 hour mode. + */ + hour = rtc_data[SD3078_REG_HR]; + if (hour & 0x80) /* 24H MODE */ + tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x3F); + else if (hour & 0x20) /* 12H MODE PM */ + tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x1F) + 12; + else /* 12H MODE AM */ + tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x1F); + + tm->tm_mday = bcd2bin(rtc_data[SD3078_REG_DM] & 0x3F); + tm->tm_wday = rtc_data[SD3078_REG_DW] & 0x07; + tm->tm_mon = bcd2bin(rtc_data[SD3078_REG_MO] & 0x1F) - 1; + tm->tm_year = bcd2bin(rtc_data[SD3078_REG_YR]) + 100; + + return 0; +} + +static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char rtc_data[NUM_TIME_REGS]; + struct i2c_client *client = to_i2c_client(dev); + struct sd3078 *sd3078 = i2c_get_clientdata(client); + int ret; + + rtc_data[SD3078_REG_SC] = bin2bcd(tm->tm_sec); + rtc_data[SD3078_REG_MN] = bin2bcd(tm->tm_min); + rtc_data[SD3078_REG_HR] = bin2bcd(tm->tm_hour) | 0x80; + rtc_data[SD3078_REG_DM] = bin2bcd(tm->tm_mday); + rtc_data[SD3078_REG_DW] = tm->tm_wday & 0x07; + rtc_data[SD3078_REG_MO] = bin2bcd(tm->tm_mon) + 1; + rtc_data[SD3078_REG_YR] = bin2bcd(tm->tm_year - 100); + +#if WRITE_PROTECT_EN + sd3078_enable_reg_write(sd3078); +#endif + + ret = regmap_bulk_write(sd3078->regmap, SD3078_REG_SC, rtc_data, + NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "writing to RTC failed with err:%d\n", ret); + return ret; + } + +#if WRITE_PROTECT_EN + sd3078_disable_reg_write(sd3078); +#endif + + return 0; +} + +static const struct rtc_class_ops sd3078_rtc_ops = { + .read_time = sd3078_rtc_read_time, + .set_time = sd3078_rtc_set_time, +}; + +static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, +}; + +static int sd3078_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct sd3078 *sd3078; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + sd3078 = devm_kzalloc(&client->dev, sizeof(*sd3078), GFP_KERNEL); + if (!sd3078) + return -ENOMEM; + + sd3078->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(sd3078->regmap)) { + dev_err(&client->dev, "regmap allocation failed\n"); + return PTR_ERR(sd3078->regmap); + } + + i2c_set_clientdata(client, sd3078); + + sd3078->rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(sd3078->rtc)) + return PTR_ERR(sd3078->rtc); + + sd3078->rtc->ops = &sd3078_rtc_ops; + sd3078->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + sd3078->rtc->range_max = RTC_TIMESTAMP_END_2099; + + ret = rtc_register_device(sd3078->rtc); + if (ret) { + dev_err(&client->dev, "failed to register rtc device\n"); + return ret; + } + + sd3078_enable_reg_write(sd3078); + + return 0; +} + +static const struct i2c_device_id sd3078_id[] = { + {"sd3078", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, sd3078_id); + +static const struct of_device_id rtc_dt_match[] = { + { .compatible = "whwave,sd3078" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtc_dt_match); + +struct i2c_driver sd3078_driver = { + .driver = { + .name = "sd3078", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtc_dt_match), + }, + .probe = sd3078_probe, + .id_table = sd3078_id, +}; + +module_i2c_driver(sd3078_driver); + +MODULE_AUTHOR("Dianlong Li "); +MODULE_DESCRIPTION("SD3078 RTC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 7c617e0c5f37d2f681b3a568c3642115a32b7427 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 18 Dec 2018 22:52:12 +0100 Subject: rtc: pcf8523: Add rv8523 compatible The Microcrystal RV-8523 is compatible with the PCF8523. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf8523.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 3fcd2cbafc84..fb13933f4006 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -374,6 +374,7 @@ MODULE_DEVICE_TABLE(i2c, pcf8523_id); #ifdef CONFIG_OF static const struct of_device_id pcf8523_of_match[] = { { .compatible = "nxp,pcf8523" }, + { .compatible = "microcrystal,rv8523" }, { } }; MODULE_DEVICE_TABLE(of, pcf8523_of_match); -- cgit v1.2.3 From 074b01a51d058f4216b7ce541e96b778aa6af60d Mon Sep 17 00:00:00 2001 From: ZhangXiaoxu Date: Thu, 20 Dec 2018 17:36:56 +0800 Subject: rtc: Fix UBSAN overflow warning Users may call 'ioctl' and pass a very big value on 'tm->tm_year'. It can be overflowed in 'int' after add 1900. In function 'rtc_month_days' and 'mktime64', also treated it as an 'unsigned' parameter. UBSAN: Undefined behaviour in drivers/rtc/rtc-lib.c:103:59 signed integer overflow: 2147483647 + 1900 cannot be represented in type 'int' UBSAN: Undefined behaviour in drivers/rtc/rtc-lib.c:119:30 signed integer overflow: 2147483647 + 1900 cannot be represented in type 'int' So, covert it to 'unsigned' explicitly. Signed-off-by: ZhangXiaoxu Signed-off-by: Alexandre Belloni --- drivers/rtc/lib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c index ef160da84220..9714cb3d1e29 100644 --- a/drivers/rtc/lib.c +++ b/drivers/rtc/lib.c @@ -100,7 +100,7 @@ int rtc_valid_tm(struct rtc_time *tm) if (tm->tm_year < 70 || ((unsigned)tm->tm_mon) >= 12 || tm->tm_mday < 1 - || tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) + || tm->tm_mday > rtc_month_days(tm->tm_mon, ((unsigned)tm->tm_year + 1900)) || ((unsigned)tm->tm_hour) >= 24 || ((unsigned)tm->tm_min) >= 60 || ((unsigned)tm->tm_sec) >= 60) @@ -116,8 +116,8 @@ EXPORT_SYMBOL(rtc_valid_tm); */ time64_t rtc_tm_to_time64(struct rtc_time *tm) { - return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + return mktime64(((unsigned)tm->tm_year + 1900), tm->tm_mon + 1, + tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } EXPORT_SYMBOL(rtc_tm_to_time64); -- cgit v1.2.3 From c8c97a4fb52c526be7a78c4c1e61a95cf1c915cc Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 2 Jan 2019 16:00:17 +0000 Subject: rtc: isl1208: fix negative digital trim reporting isl1208_i2c_get_dtr() was returning the dtr value directly, but could also return a negative error code. Negative trimming values, e.g. -20, would get interpreted as an error code, e.g. -ENOTDIR. This patch offsets the dtr value by 100 so it's positive and won't alias an error code. Also fix check that considered a return value of -1 to be success. Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Trent Piepho Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 37ab3e1d25f5..263af3d8cd9f 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -161,6 +161,7 @@ isl1208_i2c_get_atr(struct i2c_client *client) return atr; } +/* returns adjustment value + 100 */ static int isl1208_i2c_get_dtr(struct i2c_client *client) { @@ -171,7 +172,7 @@ isl1208_i2c_get_dtr(struct i2c_client *client) /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1); - return dtr; + return dtr + 100; } static int @@ -248,8 +249,8 @@ isl1208_rtc_proc(struct device *dev, struct seq_file *seq) (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay"); dtr = isl1208_i2c_get_dtr(client); - if (dtr >= 0 - 1) - seq_printf(seq, "digital_trim\t: %d ppm\n", dtr); + if (dtr >= 0) + seq_printf(seq, "digital_trim\t: %d ppm\n", dtr - 100); atr = isl1208_i2c_get_atr(client); if (atr >= 0) @@ -637,7 +638,7 @@ isl1208_sysfs_show_dtrim(struct device *dev, if (dtr < 0) return dtr; - return sprintf(buf, "%d ppm\n", dtr); + return sprintf(buf, "%d ppm\n", dtr - 100); } static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); -- cgit v1.2.3 From 6fa8f1afd3373c456e556815ebc8cb2330d6c3fe Mon Sep 17 00:00:00 2001 From: Shamir Rabinovitch Date: Wed, 9 Jan 2019 11:15:15 +0200 Subject: IB/{core,uverbs}: Move ib_umem_xxx functions from ib_core to ib_uverbs The next patch will add dependency from ib_umem_get in to ib_uverbs so move the required ib_umem_xxx functionality to it's correct module - ib_uverbs - and avoid circular dependecy from the form of ib_core -> ib_uverbs -> ib_core in depmod. Since this now requires all drivers to be build modular if uverbs is modular, hoist the test a couple drivers had into the main kconfig and apply it to all drivers uniformly. Signed-off-by: Shamir Rabinovitch Signed-off-by: Jason Gunthorpe --- drivers/infiniband/Kconfig | 15 +++++++-------- drivers/infiniband/core/Makefile | 4 ++-- drivers/infiniband/hw/hns/Kconfig | 1 - drivers/infiniband/hw/mlx4/Kconfig | 1 - drivers/infiniband/hw/mlx5/Kconfig | 1 - drivers/infiniband/hw/nes/Kconfig | 2 +- 6 files changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 0a3ec7c726ec..a1fb840de45d 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -89,6 +89,7 @@ config INFINIBAND_ADDR_TRANS_CONFIGFS This allows the user to config the default GID type that the CM uses for each device, when initiaing new connections. +if INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS source "drivers/infiniband/hw/mthca/Kconfig" source "drivers/infiniband/hw/qib/Kconfig" source "drivers/infiniband/hw/cxgb3/Kconfig" @@ -101,6 +102,12 @@ source "drivers/infiniband/hw/ocrdma/Kconfig" source "drivers/infiniband/hw/vmw_pvrdma/Kconfig" source "drivers/infiniband/hw/usnic/Kconfig" source "drivers/infiniband/hw/hns/Kconfig" +source "drivers/infiniband/hw/bnxt_re/Kconfig" +source "drivers/infiniband/hw/hfi1/Kconfig" +source "drivers/infiniband/hw/qedr/Kconfig" +source "drivers/infiniband/sw/rdmavt/Kconfig" +source "drivers/infiniband/sw/rxe/Kconfig" +endif source "drivers/infiniband/ulp/ipoib/Kconfig" @@ -111,13 +118,5 @@ source "drivers/infiniband/ulp/iser/Kconfig" source "drivers/infiniband/ulp/isert/Kconfig" source "drivers/infiniband/ulp/opa_vnic/Kconfig" -source "drivers/infiniband/sw/rdmavt/Kconfig" -source "drivers/infiniband/sw/rxe/Kconfig" - -source "drivers/infiniband/hw/hfi1/Kconfig" - -source "drivers/infiniband/hw/qedr/Kconfig" - -source "drivers/infiniband/hw/bnxt_re/Kconfig" endif # INFINIBAND diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 69dee36e0e89..313f2349b518 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -15,8 +15,6 @@ ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \ nldev.o restrack.o ib_core-$(CONFIG_SECURITY_INFINIBAND) += security.o -ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o -ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o ib_cm-y := cm.o @@ -39,3 +37,5 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \ uverbs_std_types_flow_action.o uverbs_std_types_dm.o \ uverbs_std_types_mr.o uverbs_std_types_counters.o \ uverbs_uapi.o uverbs_std_types_device.o +ib_uverbs-$(CONFIG_INFINIBAND_USER_MEM) += umem.o +ib_uverbs-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o diff --git a/drivers/infiniband/hw/hns/Kconfig b/drivers/infiniband/hw/hns/Kconfig index 21c2100b2ea9..fddb5fdf92de 100644 --- a/drivers/infiniband/hw/hns/Kconfig +++ b/drivers/infiniband/hw/hns/Kconfig @@ -1,7 +1,6 @@ config INFINIBAND_HNS tristate "HNS RoCE Driver" depends on NET_VENDOR_HISILICON - depends on INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS depends on ARM64 || (COMPILE_TEST && 64BIT) ---help--- This is a RoCE/RDMA driver for the Hisilicon RoCE engine. The engine diff --git a/drivers/infiniband/hw/mlx4/Kconfig b/drivers/infiniband/hw/mlx4/Kconfig index d1de3285fd88..db4aa13ebae0 100644 --- a/drivers/infiniband/hw/mlx4/Kconfig +++ b/drivers/infiniband/hw/mlx4/Kconfig @@ -1,7 +1,6 @@ config MLX4_INFINIBAND tristate "Mellanox ConnectX HCA support" depends on NETDEVICES && ETHERNET && PCI && INET - depends on INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS depends on MAY_USE_DEVLINK select NET_VENDOR_MELLANOX select MLX4_CORE diff --git a/drivers/infiniband/hw/mlx5/Kconfig b/drivers/infiniband/hw/mlx5/Kconfig index 0440966bc6ec..8d651c05de62 100644 --- a/drivers/infiniband/hw/mlx5/Kconfig +++ b/drivers/infiniband/hw/mlx5/Kconfig @@ -1,7 +1,6 @@ config MLX5_INFINIBAND tristate "Mellanox 5th generation network adapters (ConnectX series) support" depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE - depends on INFINIBAND_USER_ACCESS || INFINIBAND_USER_ACCESS=n ---help--- This driver provides low-level InfiniBand support for Mellanox Connect-IB PCI Express host channel adapters (HCAs). diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig index 7964eba8e7ed..52caae954e4a 100644 --- a/drivers/infiniband/hw/nes/Kconfig +++ b/drivers/infiniband/hw/nes/Kconfig @@ -1,6 +1,6 @@ config INFINIBAND_NES tristate "NetEffect RNIC Driver" - depends on PCI && INET && INFINIBAND + depends on PCI && INET select LIBCRC32C ---help--- This is the RDMA Network Interface Card (RNIC) driver for -- cgit v1.2.3 From b0ea0fa5435f9df7213a9af098558f7dd584d8e8 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 9 Jan 2019 11:15:16 +0200 Subject: IB/{core,hw}: Have ib_umem_get extract the ib_ucontext from ib_udata ib_umem_get() can only be called in a method callback, which always has a udata parameter. This allows ib_umem_get() to derive the ucontext pointer directly from the udata without requiring the drivers to find it in some way or another. Signed-off-by: Jason Gunthorpe Signed-off-by: Shamir Rabinovitch --- drivers/infiniband/core/umem.c | 9 ++++-- drivers/infiniband/core/uverbs_main.c | 24 ++++++++++++++++ drivers/infiniband/hw/bnxt_re/ib_verbs.c | 13 ++++----- drivers/infiniband/hw/cxgb3/iwch_provider.c | 2 +- drivers/infiniband/hw/cxgb4/mem.c | 2 +- drivers/infiniband/hw/hns/hns_roce_cq.c | 9 +++--- drivers/infiniband/hw/hns/hns_roce_db.c | 6 ++-- drivers/infiniband/hw/hns/hns_roce_device.h | 3 +- drivers/infiniband/hw/hns/hns_roce_mr.c | 7 ++--- drivers/infiniband/hw/hns/hns_roce_qp.c | 13 ++++----- drivers/infiniband/hw/hns/hns_roce_srq.c | 7 ++--- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 2 +- drivers/infiniband/hw/mlx4/cq.c | 17 ++++++------ drivers/infiniband/hw/mlx4/doorbell.c | 6 ++-- drivers/infiniband/hw/mlx4/mlx4_ib.h | 3 +- drivers/infiniband/hw/mlx4/mr.c | 11 ++++---- drivers/infiniband/hw/mlx4/qp.c | 14 ++++++---- drivers/infiniband/hw/mlx4/srq.c | 5 ++-- drivers/infiniband/hw/mlx5/cq.c | 11 ++++---- drivers/infiniband/hw/mlx5/devx.c | 2 +- drivers/infiniband/hw/mlx5/doorbell.c | 6 ++-- drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 ++- drivers/infiniband/hw/mlx5/mr.c | 22 +++++++-------- drivers/infiniband/hw/mlx5/odp.c | 4 +-- drivers/infiniband/hw/mlx5/qp.c | 40 ++++++++++++--------------- drivers/infiniband/hw/mlx5/srq.c | 5 ++-- drivers/infiniband/hw/mthca/mthca_provider.c | 2 +- drivers/infiniband/hw/nes/nes_verbs.c | 2 +- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 2 +- drivers/infiniband/hw/qedr/verbs.c | 33 +++++++++++----------- drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c | 2 +- drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c | 3 +- drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c | 6 ++-- drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c | 4 +-- drivers/infiniband/sw/rdmavt/mr.c | 3 +- drivers/infiniband/sw/rxe/rxe_mr.c | 2 +- 36 files changed, 162 insertions(+), 144 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index c6144df47ea4..1efe0a74e06b 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -72,15 +72,16 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d * If access flags indicate ODP memory, avoid pinning. Instead, stores * the mm for future page fault handling in conjunction with MMU notifiers. * - * @context: userspace context to pin memory for + * @udata: userspace context to pin memory for * @addr: userspace virtual address to start at * @size: length of region to pin * @access: IB_ACCESS_xxx flags for memory being pinned * @dmasync: flush in-flight DMA when the memory region is written */ -struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, +struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr, size_t size, int access, int dmasync) { + struct ib_ucontext *context; struct ib_umem *umem; struct page **page_list; struct vm_area_struct **vma_list; @@ -95,6 +96,10 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, struct scatterlist *sg, *sg_list_start; unsigned int gup_flags = FOLL_WRITE; + context = rdma_get_ucontext(udata); + if (IS_ERR(context)) + return ERR_CAST(context); + if (dmasync) dma_attrs |= DMA_ATTR_WRITE_BARRIER; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index fb0007aa0c27..996f167d1436 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -101,6 +101,30 @@ struct ib_ucontext *ib_uverbs_get_ucontext_file(struct ib_uverbs_file *ufile) } EXPORT_SYMBOL(ib_uverbs_get_ucontext_file); +/* rdma_get_ucontext - Return the ucontext from a udata + * @udata: The udata to get the context from + * + * This can only be called from within a uapi method that was passed ib_udata + * as a parameter. It returns the ucontext associated with the udata, or ERR_PTR + * if the udata is NULL or the ucontext has been disassociated. + */ +struct ib_ucontext *rdma_get_ucontext(struct ib_udata *udata) +{ + if (!udata) + return ERR_PTR(-EIO); + + /* + * FIXME: Really all cases that get here with a udata will have + * already called ib_uverbs_get_ucontext_file, or located a uobject + * that points to a ucontext. We could store that result in the udata + * so this function can't fail. + */ + return ib_uverbs_get_ucontext_file( + container_of(udata, struct uverbs_attr_bundle, driver_udata) + ->ufile); +} +EXPORT_SYMBOL(rdma_get_ucontext); + int uverbs_dealloc_mw(struct ib_mw *mw) { struct ib_pd *pd = mw->pd; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 1e2515e2eb62..9bc637e49faa 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -895,8 +895,7 @@ static int bnxt_re_init_user_qp(struct bnxt_re_dev *rdev, struct bnxt_re_pd *pd, if (qplib_qp->type == CMDQ_CREATE_QP_TYPE_RC) bytes += (qplib_qp->sq.max_wqe * sizeof(struct sq_psn_search)); bytes = PAGE_ALIGN(bytes); - umem = ib_umem_get(context, ureq.qpsva, bytes, - IB_ACCESS_LOCAL_WRITE, 1); + umem = ib_umem_get(udata, ureq.qpsva, bytes, IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(umem)) return PTR_ERR(umem); @@ -908,7 +907,7 @@ static int bnxt_re_init_user_qp(struct bnxt_re_dev *rdev, struct bnxt_re_pd *pd, if (!qp->qplib_qp.srq) { bytes = (qplib_qp->rq.max_wqe * BNXT_QPLIB_MAX_RQE_ENTRY_SIZE); bytes = PAGE_ALIGN(bytes); - umem = ib_umem_get(context, ureq.qprva, bytes, + umem = ib_umem_get(udata, ureq.qprva, bytes, IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(umem)) goto rqfail; @@ -1370,8 +1369,7 @@ static int bnxt_re_init_user_srq(struct bnxt_re_dev *rdev, bytes = (qplib_srq->max_wqe * BNXT_QPLIB_MAX_RQE_ENTRY_SIZE); bytes = PAGE_ALIGN(bytes); - umem = ib_umem_get(context, ureq.srqva, bytes, - IB_ACCESS_LOCAL_WRITE, 1); + umem = ib_umem_get(udata, ureq.srqva, bytes, IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(umem)) return PTR_ERR(umem); @@ -2622,7 +2620,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev, goto fail; } - cq->umem = ib_umem_get(context, req.cq_va, + cq->umem = ib_umem_get(udata, req.cq_va, entries * sizeof(struct cq_base), IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(cq->umem)) { @@ -3589,8 +3587,7 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, /* The fixed portion of the rkey is the same as the lkey */ mr->ib_mr.rkey = mr->qplib_mr.rkey; - umem = ib_umem_get(ib_pd->uobject->context, start, length, - mr_access_flags, 0); + umem = ib_umem_get(udata, start, length, mr_access_flags, 0); if (IS_ERR(umem)) { dev_err(rdev_to_dev(rdev), "Failed to get umem"); rc = -EFAULT; diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index b34b1a1bd94b..92ee6761a3bd 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -540,7 +540,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, mhp->rhp = rhp; - mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); + mhp->umem = ib_umem_get(udata, start, length, acc, 0); if (IS_ERR(mhp->umem)) { err = PTR_ERR(mhp->umem); kfree(mhp); diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index 7b76e6f81aeb..96760a36b9fc 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -537,7 +537,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, mhp->rhp = rhp; - mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); + mhp->umem = ib_umem_get(udata, start, length, acc, 0); if (IS_ERR(mhp->umem)) goto err_free_skb; diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 3a485f50fede..1dfe5627006c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -215,7 +215,7 @@ void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) EXPORT_SYMBOL_GPL(hns_roce_free_cq); static int hns_roce_ib_get_cq_umem(struct hns_roce_dev *hr_dev, - struct ib_ucontext *context, + struct ib_udata *udata, struct hns_roce_cq_buf *buf, struct ib_umem **umem, u64 buf_addr, int cqe) { @@ -223,7 +223,7 @@ static int hns_roce_ib_get_cq_umem(struct hns_roce_dev *hr_dev, u32 page_shift; u32 npages; - *umem = ib_umem_get(context, buf_addr, cqe * hr_dev->caps.cq_entry_sz, + *umem = ib_umem_get(udata, buf_addr, cqe * hr_dev->caps.cq_entry_sz, IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(*umem)) return PTR_ERR(*umem); @@ -347,7 +347,7 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, } /* Get user space address, write it into mtt table */ - ret = hns_roce_ib_get_cq_umem(hr_dev, context, &hr_cq->hr_buf, + ret = hns_roce_ib_get_cq_umem(hr_dev, udata, &hr_cq->hr_buf, &hr_cq->umem, ucmd.buf_addr, cq_entries); if (ret) { @@ -358,7 +358,8 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) && (udata->outlen >= sizeof(resp))) { ret = hns_roce_db_map_user(to_hr_ucontext(context), - ucmd.db_addr, &hr_cq->db); + udata, ucmd.db_addr, + &hr_cq->db); if (ret) { dev_err(dev, "cq record doorbell map failed!\n"); goto err_mtt; diff --git a/drivers/infiniband/hw/hns/hns_roce_db.c b/drivers/infiniband/hw/hns/hns_roce_db.c index e2f93c1ce86a..0c6c1fe87705 100644 --- a/drivers/infiniband/hw/hns/hns_roce_db.c +++ b/drivers/infiniband/hw/hns/hns_roce_db.c @@ -8,7 +8,8 @@ #include #include "hns_roce_device.h" -int hns_roce_db_map_user(struct hns_roce_ucontext *context, unsigned long virt, +int hns_roce_db_map_user(struct hns_roce_ucontext *context, + struct ib_udata *udata, unsigned long virt, struct hns_roce_db *db) { struct hns_roce_user_db_page *page; @@ -28,8 +29,7 @@ int hns_roce_db_map_user(struct hns_roce_ucontext *context, unsigned long virt, refcount_set(&page->refcount, 1); page->user_virt = (virt & PAGE_MASK); - page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, - PAGE_SIZE, 0, 0); + page->umem = ib_umem_get(udata, virt & PAGE_MASK, PAGE_SIZE, 0, 0); if (IS_ERR(page->umem)) { ret = PTR_ERR(page->umem); kfree(page); diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 509e467843f6..9a4be70936e0 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -1133,7 +1133,8 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, int hns_roce_ib_destroy_cq(struct ib_cq *ib_cq); void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq); -int hns_roce_db_map_user(struct hns_roce_ucontext *context, unsigned long virt, +int hns_roce_db_map_user(struct hns_roce_ucontext *context, + struct ib_udata *udata, unsigned long virt, struct hns_roce_db *db); void hns_roce_db_unmap_user(struct hns_roce_ucontext *context, struct hns_roce_db *db); diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index ee5991bd4171..da4fffedb879 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -1110,8 +1110,7 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = ib_umem_get(pd->uobject->context, start, length, - access_flags, 0); + mr->umem = ib_umem_get(udata, start, length, access_flags, 0); if (IS_ERR(mr->umem)) { ret = PTR_ERR(mr->umem); goto err_free; @@ -1220,8 +1219,8 @@ int hns_roce_rereg_user_mr(struct ib_mr *ibmr, int flags, u64 start, u64 length, } ib_umem_release(mr->umem); - mr->umem = ib_umem_get(ibmr->uobject->context, start, length, - mr_access_flags, 0); + mr->umem = + ib_umem_get(udata, start, length, mr_access_flags, 0); if (IS_ERR(mr->umem)) { ret = PTR_ERR(mr->umem); mr->umem = NULL; diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index b9ba140b50d4..accf9ce1507d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -613,9 +613,8 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, goto err_rq_sge_list; } - hr_qp->umem = ib_umem_get(ib_pd->uobject->context, - ucmd.buf_addr, hr_qp->buff_size, 0, - 0); + hr_qp->umem = ib_umem_get(udata, ucmd.buf_addr, + hr_qp->buff_size, 0, 0); if (IS_ERR(hr_qp->umem)) { dev_err(dev, "ib_umem_get error for create qp\n"); ret = PTR_ERR(hr_qp->umem); @@ -654,8 +653,8 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, (udata->outlen >= sizeof(resp)) && hns_roce_qp_has_sq(init_attr)) { ret = hns_roce_db_map_user( - to_hr_ucontext(ib_pd->uobject->context), - ucmd.sdb_addr, &hr_qp->sdb); + to_hr_ucontext(ib_pd->uobject->context), udata, + ucmd.sdb_addr, &hr_qp->sdb); if (ret) { dev_err(dev, "sq record doorbell map failed!\n"); goto err_mtt; @@ -670,8 +669,8 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, (udata->outlen >= sizeof(resp)) && hns_roce_qp_has_rq(init_attr)) { ret = hns_roce_db_map_user( - to_hr_ucontext(ib_pd->uobject->context), - ucmd.db_addr, &hr_qp->rdb); + to_hr_ucontext(ib_pd->uobject->context), udata, + ucmd.db_addr, &hr_qp->rdb); if (ret) { dev_err(dev, "rq record doorbell map failed!\n"); goto err_sq_dbmap; diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c index 960b1946c365..8975f858b36f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_srq.c +++ b/drivers/infiniband/hw/hns/hns_roce_srq.c @@ -252,8 +252,8 @@ struct ib_srq *hns_roce_create_srq(struct ib_pd *pd, goto err_srq; } - srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - srq_buf_size, 0, 0); + srq->umem = + ib_umem_get(udata, ucmd.buf_addr, srq_buf_size, 0, 0); if (IS_ERR(srq->umem)) { ret = PTR_ERR(srq->umem); goto err_srq; @@ -280,8 +280,7 @@ struct ib_srq *hns_roce_create_srq(struct ib_pd *pd, goto err_srq_mtt; /* config index queue BA */ - srq->idx_que.umem = ib_umem_get(pd->uobject->context, - ucmd.que_addr, + srq->idx_que.umem = ib_umem_get(udata, ucmd.que_addr, srq->idx_que.buf_size, 0, 0); if (IS_ERR(srq->idx_que.umem)) { dev_err(hr_dev->dev, diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 0b675b0742c2..80b66df95362 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -1852,7 +1852,7 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, if (length > I40IW_MAX_MR_SIZE) return ERR_PTR(-EINVAL); - region = ib_umem_get(pd->uobject->context, start, length, acc, 0); + region = ib_umem_get(udata, start, length, acc, 0); if (IS_ERR(region)) return (struct ib_mr *)region; diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 43512347b4f0..db936c12b5bd 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -134,16 +134,16 @@ static void mlx4_ib_free_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf * mlx4_buf_free(dev->dev, (cqe + 1) * buf->entry_size, &buf->buf); } -static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_ucontext *context, - struct mlx4_ib_cq_buf *buf, struct ib_umem **umem, - u64 buf_addr, int cqe) +static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_udata *udata, + struct mlx4_ib_cq_buf *buf, + struct ib_umem **umem, u64 buf_addr, int cqe) { int err; int cqe_size = dev->dev->caps.cqe_size; int shift; int n; - *umem = ib_umem_get(context, buf_addr, cqe * cqe_size, + *umem = ib_umem_get(udata, buf_addr, cqe * cqe_size, IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(*umem)) return PTR_ERR(*umem); @@ -213,14 +213,13 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, } buf_addr = (void *)(unsigned long)ucmd.buf_addr; - - err = mlx4_ib_get_cq_umem(dev, context, &cq->buf, &cq->umem, + err = mlx4_ib_get_cq_umem(dev, udata, &cq->buf, &cq->umem, ucmd.buf_addr, entries); if (err) goto err_cq; - err = mlx4_ib_db_map_user(to_mucontext(context), ucmd.db_addr, - &cq->db); + err = mlx4_ib_db_map_user(to_mucontext(context), udata, + ucmd.db_addr, &cq->db); if (err) goto err_mtt; @@ -336,7 +335,7 @@ static int mlx4_alloc_resize_umem(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq if (!cq->resize_buf) return -ENOMEM; - err = mlx4_ib_get_cq_umem(dev, cq->umem->context, &cq->resize_buf->buf, + err = mlx4_ib_get_cq_umem(dev, udata, &cq->resize_buf->buf, &cq->resize_umem, ucmd.buf_addr, entries); if (err) { kfree(cq->resize_buf); diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c index c51740986367..3aab71b29ce8 100644 --- a/drivers/infiniband/hw/mlx4/doorbell.c +++ b/drivers/infiniband/hw/mlx4/doorbell.c @@ -41,7 +41,8 @@ struct mlx4_ib_user_db_page { int refcnt; }; -int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, +int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, + struct ib_udata *udata, unsigned long virt, struct mlx4_db *db) { struct mlx4_ib_user_db_page *page; @@ -61,8 +62,7 @@ int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, page->user_virt = (virt & PAGE_MASK); page->refcnt = 0; - page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, - PAGE_SIZE, 0, 0); + page->umem = ib_umem_get(udata, virt & PAGE_MASK, PAGE_SIZE, 0, 0); if (IS_ERR(page->umem)) { err = PTR_ERR(page->umem); kfree(page); diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index e491f3eda6e7..60dc1347c5ab 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -722,7 +722,8 @@ static inline u8 mlx4_ib_bond_next_port(struct mlx4_ib_dev *dev) int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev); void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev); -int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, +int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, + struct ib_udata *udata, unsigned long virt, struct mlx4_db *db); void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index c7c85c22e4e3..56639ecd53ad 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -367,7 +367,8 @@ end: return block_shift; } -static struct ib_umem *mlx4_get_umem_mr(struct ib_ucontext *context, u64 start, +static struct ib_umem *mlx4_get_umem_mr(struct ib_ucontext *context, + struct ib_udata *udata, u64 start, u64 length, u64 virt_addr, int access_flags) { @@ -398,7 +399,7 @@ static struct ib_umem *mlx4_get_umem_mr(struct ib_ucontext *context, u64 start, up_read(¤t->mm->mmap_sem); } - return ib_umem_get(context, start, length, access_flags, 0); + return ib_umem_get(udata, start, length, access_flags, 0); } struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, @@ -415,7 +416,7 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = mlx4_get_umem_mr(pd->uobject->context, start, length, + mr->umem = mlx4_get_umem_mr(pd->uobject->context, udata, start, length, virt_addr, access_flags); if (IS_ERR(mr->umem)) { err = PTR_ERR(mr->umem); @@ -506,8 +507,8 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags, mlx4_mr_rereg_mem_cleanup(dev->dev, &mmr->mmr); ib_umem_release(mmr->umem); mmr->umem = - mlx4_get_umem_mr(mr->uobject->context, start, length, - virt_addr, mr_access_flags); + mlx4_get_umem_mr(mr->uobject->context, udata, start, + length, virt_addr, mr_access_flags); if (IS_ERR(mmr->umem)) { err = PTR_ERR(mmr->umem); /* Prevent mlx4_ib_dereg_mr from free'ing invalid pointer */ diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 971e9a9ebdaf..e38bab50cecf 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1015,9 +1015,11 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, (qp->sq.wqe_cnt << qp->sq.wqe_shift); } - qp->umem = ib_umem_get(pd->uobject->context, - (src == MLX4_IB_QP_SRC) ? ucmd.qp.buf_addr : - ucmd.wq.buf_addr, qp->buf_size, 0, 0); + qp->umem = + ib_umem_get(udata, + (src == MLX4_IB_QP_SRC) ? ucmd.qp.buf_addr : + ucmd.wq.buf_addr, + qp->buf_size, 0, 0); if (IS_ERR(qp->umem)) { err = PTR_ERR(qp->umem); goto err; @@ -1035,9 +1037,11 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, goto err_mtt; if (qp_has_rq(init_attr)) { - err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context), + err = mlx4_ib_db_map_user( + to_mucontext(pd->uobject->context), udata, (src == MLX4_IB_QP_SRC) ? ucmd.qp.db_addr : - ucmd.wq.db_addr, &qp->db); + ucmd.wq.db_addr, + &qp->db); if (err) goto err_mtt; } diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 4456f1b8921d..498588eac051 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c @@ -113,8 +113,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, goto err_srq; } - srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - buf_size, 0, 0); + srq->umem = ib_umem_get(udata, ucmd.buf_addr, buf_size, 0, 0); if (IS_ERR(srq->umem)) { err = PTR_ERR(srq->umem); goto err_srq; @@ -130,7 +129,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, goto err_mtt; err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context), - ucmd.db_addr, &srq->db); + udata, ucmd.db_addr, &srq->db); if (err) goto err_mtt; } else { diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 90f1b0bae5b5..c283c32f30fe 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -707,15 +707,15 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, *cqe_size = ucmd.cqe_size; - cq->buf.umem = ib_umem_get(context, ucmd.buf_addr, - entries * ucmd.cqe_size, - IB_ACCESS_LOCAL_WRITE, 1); + cq->buf.umem = + ib_umem_get(udata, ucmd.buf_addr, entries * ucmd.cqe_size, + IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(cq->buf.umem)) { err = PTR_ERR(cq->buf.umem); return err; } - err = mlx5_ib_db_map_user(to_mucontext(context), ucmd.db_addr, + err = mlx5_ib_db_map_user(to_mucontext(context), udata, ucmd.db_addr, &cq->db); if (err) goto err_umem; @@ -1111,7 +1111,6 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, struct ib_umem *umem; int err; int npages; - struct ib_ucontext *context = cq->buf.umem->context; err = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)); if (err) @@ -1124,7 +1123,7 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1) return -EINVAL; - umem = ib_umem_get(context, ucmd.buf_addr, + umem = ib_umem_get(udata, ucmd.buf_addr, (size_t)ucmd.cqe_size * entries, IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(umem)) { diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 5a588f3cfb1b..8bb711da7ee1 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -1195,7 +1195,7 @@ static int devx_umem_get(struct mlx5_ib_dev *dev, struct ib_ucontext *ucontext, if (err) return err; - obj->umem = ib_umem_get(ucontext, addr, size, access, 0); + obj->umem = ib_umem_get(&attrs->driver_udata, addr, size, access, 0); if (IS_ERR(obj->umem)) return PTR_ERR(obj->umem); diff --git a/drivers/infiniband/hw/mlx5/doorbell.c b/drivers/infiniband/hw/mlx5/doorbell.c index a0e4e6ddb71a..8f4e5f22b84c 100644 --- a/drivers/infiniband/hw/mlx5/doorbell.c +++ b/drivers/infiniband/hw/mlx5/doorbell.c @@ -43,7 +43,8 @@ struct mlx5_ib_user_db_page { int refcnt; }; -int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt, +int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, + struct ib_udata *udata, unsigned long virt, struct mlx5_db *db) { struct mlx5_ib_user_db_page *page; @@ -63,8 +64,7 @@ int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt, page->user_virt = (virt & PAGE_MASK); page->refcnt = 0; - page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, - PAGE_SIZE, 0, 0); + page->umem = ib_umem_get(udata, virt & PAGE_MASK, PAGE_SIZE, 0, 0); if (IS_ERR(page->umem)) { err = PTR_ERR(page->umem); kfree(page); diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 81efa5def8ad..b0a37ca2a714 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -1037,7 +1037,8 @@ to_mflow_act(struct ib_flow_action *ibact) return container_of(ibact, struct mlx5_ib_flow_action, ib_action); } -int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt, +int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, + struct ib_udata *udata, unsigned long virt, struct mlx5_db *db); void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db); void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq); @@ -1103,6 +1104,7 @@ int mlx5_ib_dealloc_mw(struct ib_mw *mw); int mlx5_ib_update_xlt(struct mlx5_ib_mr *mr, u64 idx, int npages, int page_shift, int flags); struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd, + struct ib_udata *udata, int access_flags); void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *mr); int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start, diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 494a90f4348c..6d763d6a189f 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -843,18 +843,17 @@ static int mr_cache_max_order(struct mlx5_ib_dev *dev) return MLX5_MAX_UMR_SHIFT; } -static int mr_umem_get(struct ib_pd *pd, u64 start, u64 length, - int access_flags, struct ib_umem **umem, - int *npages, int *page_shift, int *ncont, - int *order) +static int mr_umem_get(struct mlx5_ib_dev *dev, struct ib_udata *udata, + u64 start, u64 length, int access_flags, + struct ib_umem **umem, int *npages, int *page_shift, + int *ncont, int *order) { - struct mlx5_ib_dev *dev = to_mdev(pd->device); struct ib_umem *u; int err; *umem = NULL; - u = ib_umem_get(pd->uobject->context, start, length, access_flags, 0); + u = ib_umem_get(udata, start, length, access_flags, 0); err = PTR_ERR_OR_ZERO(u); if (err) { mlx5_ib_dbg(dev, "umem get failed (%d)\n", err); @@ -1333,14 +1332,14 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, !(dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT)) return ERR_PTR(-EINVAL); - mr = mlx5_ib_alloc_implicit_mr(to_mpd(pd), access_flags); + mr = mlx5_ib_alloc_implicit_mr(to_mpd(pd), udata, access_flags); if (IS_ERR(mr)) return ERR_CAST(mr); return &mr->ibmr; } - err = mr_umem_get(pd, start, length, access_flags, &umem, &npages, - &page_shift, &ncont, &order); + err = mr_umem_get(dev, udata, start, length, access_flags, &umem, + &npages, &page_shift, &ncont, &order); if (err < 0) return ERR_PTR(err); @@ -1488,8 +1487,9 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start, flags |= IB_MR_REREG_TRANS; ib_umem_release(mr->umem); mr->umem = NULL; - err = mr_umem_get(pd, addr, len, access_flags, &mr->umem, - &npages, &page_shift, &ncont, &order); + err = mr_umem_get(dev, udata, addr, len, access_flags, + &mr->umem, &npages, &page_shift, &ncont, + &order); if (err) goto err; } diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index 37d6653f9636..8d46b1dc5658 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -492,13 +492,13 @@ next_mr: } struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd, + struct ib_udata *udata, int access_flags) { - struct ib_ucontext *ctx = pd->ibpd.uobject->context; struct mlx5_ib_mr *imr; struct ib_umem *umem; - umem = ib_umem_get(ctx, 0, 0, IB_ACCESS_ON_DEMAND, 0); + umem = ib_umem_get(udata, 0, 0, IB_ACCESS_ON_DEMAND, 0); if (IS_ERR(umem)) return ERR_CAST(umem); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index dd2ae640bc84..529e76f67cb6 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -645,16 +645,14 @@ int bfregn_to_uar_index(struct mlx5_ib_dev *dev, return bfregi->sys_pages[index_of_sys_page] + offset; } -static int mlx5_ib_umem_get(struct mlx5_ib_dev *dev, - struct ib_pd *pd, +static int mlx5_ib_umem_get(struct mlx5_ib_dev *dev, struct ib_udata *udata, unsigned long addr, size_t size, - struct ib_umem **umem, - int *npages, int *page_shift, int *ncont, - u32 *offset) + struct ib_umem **umem, int *npages, int *page_shift, + int *ncont, u32 *offset) { int err; - *umem = ib_umem_get(pd->uobject->context, addr, size, 0, 0); + *umem = ib_umem_get(udata, addr, size, 0, 0); if (IS_ERR(*umem)) { mlx5_ib_dbg(dev, "umem_get failed\n"); return PTR_ERR(*umem); @@ -695,10 +693,9 @@ static void destroy_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd, } static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd, - struct mlx5_ib_rwq *rwq, + struct ib_udata *udata, struct mlx5_ib_rwq *rwq, struct mlx5_ib_create_wq *ucmd) { - struct mlx5_ib_ucontext *context; int page_shift = 0; int npages; u32 offset = 0; @@ -708,9 +705,7 @@ static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd, if (!ucmd->buf_addr) return -EINVAL; - context = to_mucontext(pd->uobject->context); - rwq->umem = ib_umem_get(pd->uobject->context, ucmd->buf_addr, - rwq->buf_size, 0, 0); + rwq->umem = ib_umem_get(udata, ucmd->buf_addr, rwq->buf_size, 0, 0); if (IS_ERR(rwq->umem)) { mlx5_ib_dbg(dev, "umem_get failed\n"); err = PTR_ERR(rwq->umem); @@ -735,7 +730,8 @@ static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd, (unsigned long long)ucmd->buf_addr, rwq->buf_size, npages, page_shift, ncont, offset); - err = mlx5_ib_db_map_user(context, ucmd->db_addr, &rwq->db); + err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context), udata, + ucmd->db_addr, &rwq->db); if (err) { mlx5_ib_dbg(dev, "map failed\n"); goto err_umem; @@ -819,10 +815,9 @@ static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, if (ucmd.buf_addr && ubuffer->buf_size) { ubuffer->buf_addr = ucmd.buf_addr; - err = mlx5_ib_umem_get(dev, pd, ubuffer->buf_addr, - ubuffer->buf_size, - &ubuffer->umem, &npages, &page_shift, - &ncont, &offset); + err = mlx5_ib_umem_get(dev, udata, ubuffer->buf_addr, + ubuffer->buf_size, &ubuffer->umem, + &npages, &page_shift, &ncont, &offset); if (err) goto err_bfreg; } else { @@ -856,7 +851,7 @@ static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, resp->bfreg_index = MLX5_IB_INVALID_BFREG; qp->bfregn = bfregn; - err = mlx5_ib_db_map_user(context, ucmd.db_addr, &qp->db); + err = mlx5_ib_db_map_user(context, udata, ucmd.db_addr, &qp->db); if (err) { mlx5_ib_dbg(dev, "map failed\n"); goto err_free; @@ -1119,6 +1114,7 @@ static void destroy_flow_rule_vport_sq(struct mlx5_ib_dev *dev, } static int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev, + struct ib_udata *udata, struct mlx5_ib_sq *sq, void *qpin, struct ib_pd *pd) { @@ -1135,9 +1131,9 @@ static int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev, int ncont = 0; u32 offset = 0; - err = mlx5_ib_umem_get(dev, pd, ubuffer->buf_addr, ubuffer->buf_size, - &sq->ubuffer.umem, &npages, &page_shift, - &ncont, &offset); + err = mlx5_ib_umem_get(dev, udata, ubuffer->buf_addr, ubuffer->buf_size, + &sq->ubuffer.umem, &npages, &page_shift, &ncont, + &offset); if (err) return err; @@ -1374,7 +1370,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, if (err) return err; - err = create_raw_packet_qp_sq(dev, sq, in, pd); + err = create_raw_packet_qp_sq(dev, udata, sq, in, pd); if (err) goto err_destroy_tis; @@ -5793,7 +5789,7 @@ static int prepare_user_rq(struct ib_pd *pd, return err; } - err = create_user_rq(dev, pd, rwq, &ucmd); + err = create_user_rq(dev, pd, udata, rwq, &ucmd); if (err) { mlx5_ib_dbg(dev, "err %d\n", err); return err; diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 4e8d18009f58..22bd774e0b4e 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -79,8 +79,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE); - srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size, - 0, 0); + srq->umem = ib_umem_get(udata, ucmd.buf_addr, buf_size, 0, 0); if (IS_ERR(srq->umem)) { mlx5_ib_dbg(dev, "failed umem get, size %d\n", buf_size); err = PTR_ERR(srq->umem); @@ -104,7 +103,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, mlx5_ib_populate_pas(dev, srq->umem, page_shift, in->pas, 0); - err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context), + err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context), udata, ucmd.db_addr, &srq->db); if (err) { mlx5_ib_dbg(dev, "map doorbell failed\n"); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 82cb6b71ac7c..53fff6aed896 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -931,7 +931,7 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, + mr->umem = ib_umem_get(udata, start, length, acc, ucmd.mr_attrs & MTHCA_MR_DMASYNC); if (IS_ERR(mr->umem)) { diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 4e7f08ee1907..feb4d259aab9 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -2134,7 +2134,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u8 stag_key; int first_page = 1; - region = ib_umem_get(pd->uobject->context, start, length, acc, 0); + region = ib_umem_get(udata, start, length, acc, 0); if (IS_ERR(region)) { return (struct ib_mr *)region; } diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index c46bed0c5513..a8b40cb7679e 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -916,7 +916,7 @@ struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len, mr = kzalloc(sizeof(*mr), GFP_KERNEL); if (!mr) return ERR_PTR(status); - mr->umem = ib_umem_get(ibpd->uobject->context, start, len, acc, 0); + mr->umem = ib_umem_get(udata, start, len, acc, 0); if (IS_ERR(mr->umem)) { status = -EFAULT; goto umem_err; diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index b342a70e2814..ba8cb6559122 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -736,11 +736,10 @@ static inline int qedr_align_cq_entries(int entries) return aligned_size / QEDR_CQE_SIZE; } -static inline int qedr_init_user_queue(struct ib_ucontext *ib_ctx, +static inline int qedr_init_user_queue(struct ib_udata *udata, struct qedr_dev *dev, - struct qedr_userq *q, - u64 buf_addr, size_t buf_len, - int access, int dmasync, + struct qedr_userq *q, u64 buf_addr, + size_t buf_len, int access, int dmasync, int alloc_and_init) { u32 fw_pages; @@ -748,7 +747,7 @@ static inline int qedr_init_user_queue(struct ib_ucontext *ib_ctx, q->buf_addr = buf_addr; q->buf_len = buf_len; - q->umem = ib_umem_get(ib_ctx, q->buf_addr, q->buf_len, access, dmasync); + q->umem = ib_umem_get(udata, q->buf_addr, q->buf_len, access, dmasync); if (IS_ERR(q->umem)) { DP_ERR(dev, "create user queue: failed ib_umem_get, got %ld\n", PTR_ERR(q->umem)); @@ -905,9 +904,9 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, cq->cq_type = QEDR_CQ_TYPE_USER; - rc = qedr_init_user_queue(ib_ctx, dev, &cq->q, ureq.addr, - ureq.len, IB_ACCESS_LOCAL_WRITE, - 1, 1); + rc = qedr_init_user_queue(udata, dev, &cq->q, ureq.addr, + ureq.len, IB_ACCESS_LOCAL_WRITE, 1, + 1); if (rc) goto err0; @@ -1344,7 +1343,7 @@ static void qedr_free_srq_kernel_params(struct qedr_srq *srq) hw_srq->phy_prod_pair_addr); } -static int qedr_init_srq_user_params(struct ib_ucontext *ib_ctx, +static int qedr_init_srq_user_params(struct ib_udata *udata, struct qedr_srq *srq, struct qedr_create_srq_ureq *ureq, int access, int dmasync) @@ -1352,14 +1351,14 @@ static int qedr_init_srq_user_params(struct ib_ucontext *ib_ctx, struct scatterlist *sg; int rc; - rc = qedr_init_user_queue(ib_ctx, srq->dev, &srq->usrq, ureq->srq_addr, + rc = qedr_init_user_queue(udata, srq->dev, &srq->usrq, ureq->srq_addr, ureq->srq_len, access, dmasync, 1); if (rc) return rc; - srq->prod_umem = ib_umem_get(ib_ctx, ureq->prod_pair_addr, - sizeof(struct rdma_srq_producers), - access, dmasync); + srq->prod_umem = + ib_umem_get(udata, ureq->prod_pair_addr, + sizeof(struct rdma_srq_producers), access, dmasync); if (IS_ERR(srq->prod_umem)) { qedr_free_pbl(srq->dev, &srq->usrq.pbl_info, srq->usrq.pbl_tbl); ib_umem_release(srq->usrq.umem); @@ -1468,7 +1467,7 @@ struct ib_srq *qedr_create_srq(struct ib_pd *ibpd, goto err0; } - rc = qedr_init_srq_user_params(ib_ctx, srq, &ureq, 0, 0); + rc = qedr_init_srq_user_params(udata, srq, &ureq, 0, 0); if (rc) goto err0; @@ -1714,14 +1713,14 @@ static int qedr_create_user_qp(struct qedr_dev *dev, } /* SQ - read access only (0), dma sync not required (0) */ - rc = qedr_init_user_queue(ib_ctx, dev, &qp->usq, ureq.sq_addr, + rc = qedr_init_user_queue(udata, dev, &qp->usq, ureq.sq_addr, ureq.sq_len, 0, 0, alloc_and_init); if (rc) return rc; if (!qp->srq) { /* RQ - read access only (0), dma sync not required (0) */ - rc = qedr_init_user_queue(ib_ctx, dev, &qp->urq, ureq.rq_addr, + rc = qedr_init_user_queue(udata, dev, &qp->urq, ureq.rq_addr, ureq.rq_len, 0, 0, alloc_and_init); if (rc) return rc; @@ -2719,7 +2718,7 @@ struct ib_mr *qedr_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len, mr->type = QEDR_MR_USER; - mr->umem = ib_umem_get(ibpd->uobject->context, start, len, acc, 0); + mr->umem = ib_umem_get(udata, start, len, acc, 0); if (IS_ERR(mr->umem)) { rc = -EFAULT; goto err0; diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c index 0f004c737620..104c7db4704f 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c @@ -141,7 +141,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, goto err_cq; } - cq->umem = ib_umem_get(context, ucmd.buf_addr, ucmd.buf_size, + cq->umem = ib_umem_get(udata, ucmd.buf_addr, ucmd.buf_size, IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(cq->umem)) { ret = PTR_ERR(cq->umem); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c index fa96fa4fb829..a85884e90e84 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c @@ -126,8 +126,7 @@ struct ib_mr *pvrdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return ERR_PTR(-EINVAL); } - umem = ib_umem_get(pd->uobject->context, start, - length, access_flags, 0); + umem = ib_umem_get(udata, start, length, access_flags, 0); if (IS_ERR(umem)) { dev_warn(&dev->pdev->dev, "could not get umem for mem region\n"); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c index 3acf74cbe266..5fc444cef011 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c @@ -262,8 +262,7 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd, if (!is_srq) { /* set qp->sq.wqe_cnt, shift, buf_size.. */ - qp->rumem = ib_umem_get(pd->uobject->context, - ucmd.rbuf_addr, + qp->rumem = ib_umem_get(udata, ucmd.rbuf_addr, ucmd.rbuf_size, 0, 0); if (IS_ERR(qp->rumem)) { ret = PTR_ERR(qp->rumem); @@ -275,8 +274,7 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd, qp->srq = to_vsrq(init_attr->srq); } - qp->sumem = ib_umem_get(pd->uobject->context, - ucmd.sbuf_addr, + qp->sumem = ib_umem_get(udata, ucmd.sbuf_addr, ucmd.sbuf_size, 0, 0); if (IS_ERR(qp->sumem)) { if (!is_srq) diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c index 06ba7c7a2235..951d9d68107a 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c @@ -153,9 +153,7 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd, goto err_srq; } - srq->umem = ib_umem_get(pd->uobject->context, - ucmd.buf_addr, - ucmd.buf_size, 0, 0); + srq->umem = ib_umem_get(udata, ucmd.buf_addr, ucmd.buf_size, 0, 0); if (IS_ERR(srq->umem)) { ret = PTR_ERR(srq->umem); goto err_srq; diff --git a/drivers/infiniband/sw/rdmavt/mr.c b/drivers/infiniband/sw/rdmavt/mr.c index 49c9541050d4..8b1c1e8dd7ef 100644 --- a/drivers/infiniband/sw/rdmavt/mr.c +++ b/drivers/infiniband/sw/rdmavt/mr.c @@ -388,8 +388,7 @@ struct ib_mr *rvt_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (length == 0) return ERR_PTR(-EINVAL); - umem = ib_umem_get(pd->uobject->context, start, length, - mr_access_flags, 0); + umem = ib_umem_get(udata, start, length, mr_access_flags, 0); if (IS_ERR(umem)) return (void *)umem; diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c index 9d3916b93f23..2438093776a0 100644 --- a/drivers/infiniband/sw/rxe/rxe_mr.c +++ b/drivers/infiniband/sw/rxe/rxe_mr.c @@ -171,7 +171,7 @@ int rxe_mem_init_user(struct rxe_pd *pd, u64 start, void *vaddr; int err; - umem = ib_umem_get(pd->ibpd.uobject->context, start, length, access, 0); + umem = ib_umem_get(udata, start, length, access, 0); if (IS_ERR(umem)) { pr_warn("err %d from rxe_umem_get\n", (int)PTR_ERR(umem)); -- cgit v1.2.3 From 4959d5da5737dd804255c75b8cea0a2929ce279a Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 7 Jan 2019 17:27:54 +0200 Subject: IB/usnic: Fix out of bounds index check in query pkey The pkey table size is one element, index should be tested for > 0 instead of > 1. Fixes: e3cf00d0a87f ("IB/usnic: Add Cisco VIC low-level hardware driver") Signed-off-by: Gal Pressman Acked-by: Parvi Kaustubhi Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index 1d4abef17e38..63c7b48774e9 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -449,7 +449,7 @@ struct net_device *usnic_get_netdev(struct ib_device *device, u8 port_num) int usnic_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > 1) + if (index > 0) return -EINVAL; *pkey = 0xffff; -- cgit v1.2.3 From b188940796c7be31c1b8c25a9a0e0842c2e7a49e Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 7 Jan 2019 17:27:55 +0200 Subject: RDMA/ocrdma: Fix out of bounds index check in query pkey The pkey table size is one element, index should be tested for > 0 instead of > 1. Fixes: fe2caefcdf58 ("RDMA/ocrdma: Add driver for Emulex OneConnect IBoE RDMA adapter") Signed-off-by: Gal Pressman Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index a8b40cb7679e..eb69e71c2053 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -55,7 +55,7 @@ int ocrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > 1) + if (index > 0) return -EINVAL; *pkey = 0xffff; -- cgit v1.2.3 From dbe30dae487e1a232158c24b432d45281c2805b7 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 7 Jan 2019 17:27:56 +0200 Subject: RDMA/qedr: Fix out of bounds index check in query pkey The pkey table size is QEDR_ROCE_PKEY_TABLE_LEN, index should be tested for >= QEDR_ROCE_PKEY_TABLE_LEN instead of > QEDR_ROCE_PKEY_TABLE_LEN. Fixes: a7efd7773e31 ("qedr: Add support for PD,PKEY and CQ verbs") Signed-off-by: Gal Pressman Acked-by: Michal Kalderon Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/qedr/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index ba8cb6559122..b27ff9408507 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -67,7 +67,7 @@ static inline int qedr_ib_copy_to_udata(struct ib_udata *udata, void *src, int qedr_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > QEDR_ROCE_PKEY_TABLE_LEN) + if (index >= QEDR_ROCE_PKEY_TABLE_LEN) return -EINVAL; *pkey = QEDR_ROCE_PKEY_DEFAULT; -- cgit v1.2.3 From 8cbfaac3d0974ecf53b28db23ea8c105f491bb35 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 9 Jan 2019 20:15:58 +0200 Subject: RDMA: Clear PD objects during their allocation As part of an audit process to update drivers to use rdma_restrack_add() ensure that PD objects is cleared before access. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_pd.c | 2 +- drivers/infiniband/hw/mlx5/main.c | 2 +- drivers/infiniband/hw/mthca/mthca_provider.c | 2 +- drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c | 2 +- drivers/infiniband/sw/rdmavt/pd.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c index e11c149da04d..4a29b2cb9bab 100644 --- a/drivers/infiniband/hw/hns/hns_roce_pd.c +++ b/drivers/infiniband/hw/hns/hns_roce_pd.c @@ -66,7 +66,7 @@ struct ib_pd *hns_roce_alloc_pd(struct ib_device *ib_dev, struct hns_roce_pd *pd; int ret; - pd = kmalloc(sizeof(*pd), GFP_KERNEL); + pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 11e9783cefcc..717e8535b41a 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2263,7 +2263,7 @@ static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev, u32 in[MLX5_ST_SZ_DW(alloc_pd_in)] = {}; u16 uid = 0; - pd = kmalloc(sizeof(*pd), GFP_KERNEL); + pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 53fff6aed896..f87ee3058c65 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -381,7 +381,7 @@ static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, struct mthca_pd *pd; int err; - pd = kmalloc(sizeof *pd, GFP_KERNEL); + pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c index 4d238d0e484b..65b6115caa55 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c @@ -457,7 +457,7 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, if (!atomic_add_unless(&dev->num_pds, 1, dev->dsr->caps.max_pd)) return ERR_PTR(-ENOMEM); - pd = kmalloc(sizeof(*pd), GFP_KERNEL); + pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) { ptr = ERR_PTR(-ENOMEM); goto err; diff --git a/drivers/infiniband/sw/rdmavt/pd.c b/drivers/infiniband/sw/rdmavt/pd.c index 8a89afff3363..dcc1870b8d23 100644 --- a/drivers/infiniband/sw/rdmavt/pd.c +++ b/drivers/infiniband/sw/rdmavt/pd.c @@ -66,7 +66,7 @@ struct ib_pd *rvt_alloc_pd(struct ib_device *ibdev, struct rvt_pd *pd; struct ib_pd *ret; - pd = kmalloc(sizeof(*pd), GFP_KERNEL); + pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) { ret = ERR_PTR(-ENOMEM); goto bail; -- cgit v1.2.3 From 0975890ebe9b40abf08fecf216aed4f92805db70 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 9 Jan 2019 20:15:59 +0200 Subject: RDMA: Clear CQ objects during their allocation As part of an audit process to update drivers to use rdma_restrack_add() ensure that CQ objects is cleared before access. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx4/cq.c | 2 +- drivers/infiniband/hw/mthca/mthca_provider.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index db936c12b5bd..03ac72339dd2 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -190,7 +190,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, if (attr->flags & ~CQ_CREATE_FLAGS_SUPPORTED) return ERR_PTR(-EINVAL); - cq = kmalloc(sizeof *cq, GFP_KERNEL); + cq = kzalloc(sizeof(*cq), GFP_KERNEL); if (!cq) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index f87ee3058c65..1fcc007d1d34 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -684,7 +684,7 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, goto err_unmap_set; } - cq = kmalloc(sizeof *cq, GFP_KERNEL); + cq = kzalloc(sizeof(*cq), GFP_KERNEL); if (!cq) { err = -ENOMEM; goto err_unmap_arm; -- cgit v1.2.3 From 081de9495c7a90560e9cc264cdcc2ff39b705843 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 9 Jan 2019 20:16:01 +0200 Subject: RDMA: Clear CTX objects during their allocation As part of an audit process to update drivers to use rdma_restrack_add() ensure that CTX objects is cleared before access. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_main.c | 2 +- drivers/infiniband/hw/mthca/mthca_provider.c | 2 +- drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 2 +- drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c | 2 +- drivers/infiniband/sw/rdmavt/vt.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index c79054ba9495..44a07fce0617 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -343,7 +343,7 @@ static struct ib_ucontext *hns_roce_alloc_ucontext(struct ib_device *ib_dev, resp.qp_tab_size = hr_dev->caps.num_qps; - context = kmalloc(sizeof(*context), GFP_KERNEL); + context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 1fcc007d1d34..0a939ea5497b 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -318,7 +318,7 @@ static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, else uresp.uarc_size = 0; - context = kmalloc(sizeof *context, GFP_KERNEL); + context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index 63c7b48774e9..432e6f6599fa 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -683,7 +683,7 @@ struct ib_ucontext *usnic_ib_alloc_ucontext(struct ib_device *ibdev, struct usnic_ib_dev *us_ibdev = to_usdev(ibdev); usnic_dbg("\n"); - context = kmalloc(sizeof(*context), GFP_KERNEL); + context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c index 65b6115caa55..e10149248ce2 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c @@ -327,7 +327,7 @@ struct ib_ucontext *pvrdma_alloc_ucontext(struct ib_device *ibdev, if (!vdev->ib_active) return ERR_PTR(-EAGAIN); - context = kmalloc(sizeof(*context), GFP_KERNEL); + context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c index aef3aa3fe667..8724a1817158 100644 --- a/drivers/infiniband/sw/rdmavt/vt.c +++ b/drivers/infiniband/sw/rdmavt/vt.c @@ -304,7 +304,7 @@ static struct ib_ucontext *rvt_alloc_ucontext(struct ib_device *ibdev, { struct rvt_ucontext *context; - context = kmalloc(sizeof(*context), GFP_KERNEL); + context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return ERR_PTR(-ENOMEM); return &context->ibucontext; -- cgit v1.2.3 From 5b3b9871cc28dbf827c41595d73595627434ff4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Thu, 10 Jan 2019 15:58:12 +0200 Subject: crypto: caam - move shared symbols in a common location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are several issues with symbols shared b/w: -caam/jr and caam/qi drivers on one hand -caam/qi2 driver on the other hand Commit 52813ab24959 ("crypto: caam/qi2 - avoid double export") fixed some of them, however compilation still fails for CRYPTO_DEV_FSL_CAAM=m and CRYPTO_DEV_FSL_DPAA2_CAAM=y. Another issue is related to dependency cycles reported by depmod when CRYPTO_DEV_FSL_CAAM=n and CRYPTO_DEV_FSL_DPAA2_CAAM=m, as mentioned in 82c7b351be3f ("Revert "arm64: defconfig: Enable FSL_MC_BUS and FSL_MC_DPIO"") To fix all these, move the symbols shared by these drivers in a common location. The only existing possibility is error.c file (note that naming doesn't help and should probably change). Fixes: 52813ab24959 ("crypto: caam/qi2 - avoid double export") Reported-by: Arnd Bergmann Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg_qi2.c | 7 ------- drivers/crypto/caam/ctrl.c | 4 ---- drivers/crypto/caam/error.c | 6 ++++++ 3 files changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 425d5d974613..cc59814afd29 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -25,13 +25,6 @@ #define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE + \ SHA512_DIGEST_SIZE * 2) -#if !IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM) -bool caam_little_end; -EXPORT_SYMBOL(caam_little_end); -bool caam_imx; -EXPORT_SYMBOL(caam_imx); -#endif - /* * This is a a cache of buffers, from which the users of CAAM QI driver * can allocate short buffers. It's speedier than doing kmalloc on the hotpath. diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 16bbc72f041a..14fb09223156 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -18,12 +18,8 @@ #include "desc_constr.h" #include "ctrl.h" -bool caam_little_end; -EXPORT_SYMBOL(caam_little_end); bool caam_dpaa2; EXPORT_SYMBOL(caam_dpaa2); -bool caam_imx; -EXPORT_SYMBOL(caam_imx); #ifdef CONFIG_CAAM_QI #include "qi.h" diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 7e8d690f2827..21a70fd32f5d 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -50,6 +50,12 @@ void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, #endif /* DEBUG */ EXPORT_SYMBOL(caam_dump_sg); +bool caam_little_end; +EXPORT_SYMBOL(caam_little_end); + +bool caam_imx; +EXPORT_SYMBOL(caam_imx); + static const struct { u8 value; const char *error_text; -- cgit v1.2.3 From 8d555c528565ad7261f0ce27c0a808ec9377ad33 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Dec 2018 02:26:14 +0000 Subject: crypto: chtls - remove set but not used variables 'err, adap, request, hws' Fixes gcc '-Wunused-but-set-variable' warning: drivers/crypto/chelsio/chtls/chtls_io.c: In function 'csk_wait_memory': drivers/crypto/chelsio/chtls/chtls_io.c:925:6: warning: variable 'sndbuf' set but not used [-Wunused-but-set-variable] drivers/crypto/chelsio/chtls/chtls_io.c: In function 'chtls_pt_recvmsg': drivers/crypto/chelsio/chtls/chtls_io.c:1411:6: warning: variable 'request' set but not used [-Wunused-but-set-variable] drivers/crypto/chelsio/chtls/chtls_io.c:1407:18: warning: variable 'adap' set but not used [-Wunused-but-set-variable] drivers/crypto/chelsio/chtls/chtls_io.c: In function 'chtls_recvmsg': drivers/crypto/chelsio/chtls/chtls_io.c:1701:6: warning: variable 'request' set but not used [-Wunused-but-set-variable] drivers/crypto/chelsio/chtls/chtls_io.c:1697:20: warning: variable 'hws' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chtls/chtls_io.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chtls/chtls_io.c b/drivers/crypto/chelsio/chtls/chtls_io.c index 18f553fcc167..1285a1bceda7 100644 --- a/drivers/crypto/chelsio/chtls/chtls_io.c +++ b/drivers/crypto/chelsio/chtls/chtls_io.c @@ -922,14 +922,13 @@ static int csk_wait_memory(struct chtls_dev *cdev, struct sock *sk, long *timeo_p) { DEFINE_WAIT_FUNC(wait, woken_wake_function); - int sndbuf, err = 0; + int err = 0; long current_timeo; long vm_wait = 0; bool noblock; current_timeo = *timeo_p; noblock = (*timeo_p ? false : true); - sndbuf = cdev->max_host_sndbuf; if (csk_mem_free(cdev, sk)) { current_timeo = (prandom_u32() % (HZ / 5)) + 2; vm_wait = (prandom_u32() % (HZ / 5)) + 2; @@ -1401,23 +1400,18 @@ static int chtls_pt_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len) { struct chtls_sock *csk = rcu_dereference_sk_user_data(sk); - struct net_device *dev = csk->egress_dev; struct chtls_hws *hws = &csk->tlshws; struct tcp_sock *tp = tcp_sk(sk); - struct adapter *adap; unsigned long avail; int buffers_freed; int copied = 0; - int request; int target; long timeo; - adap = netdev2adap(dev); buffers_freed = 0; timeo = sock_rcvtimeo(sk, nonblock); target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); - request = len; if (unlikely(csk_flag(sk, CSK_UPDATE_RCV_WND))) chtls_cleanup_rbuf(sk, copied); @@ -1694,11 +1688,9 @@ int chtls_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, { struct tcp_sock *tp = tcp_sk(sk); struct chtls_sock *csk; - struct chtls_hws *hws; unsigned long avail; /* amount of available data in current skb */ int buffers_freed; int copied = 0; - int request; long timeo; int target; /* Read at least this many bytes */ @@ -1718,7 +1710,6 @@ int chtls_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, lock_sock(sk); csk = rcu_dereference_sk_user_data(sk); - hws = &csk->tlshws; if (is_tls_rx(csk)) return chtls_pt_recvmsg(sk, msg, len, nonblock, @@ -1726,7 +1717,6 @@ int chtls_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, timeo = sock_rcvtimeo(sk, nonblock); target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); - request = len; if (unlikely(csk_flag(sk, CSK_UPDATE_RCV_WND))) chtls_cleanup_rbuf(sk, copied); -- cgit v1.2.3 From fa5cd1c72e32bd4f9c52626d9a9a2b0ca635b3bc Mon Sep 17 00:00:00 2001 From: "Hook, Gary" Date: Tue, 18 Dec 2018 15:48:29 +0000 Subject: crypto: ccp - Update copyright notices and dates Correct copyright dates for files that have had code added to them in 2018. Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-aes-cmac.c | 2 +- drivers/crypto/ccp/ccp-crypto-sha.c | 2 +- drivers/crypto/ccp/ccp-ops.c | 2 +- drivers/crypto/ccp/psp-dev.c | 2 +- drivers/crypto/ccp/psp-dev.h | 2 +- drivers/crypto/ccp/sp-dev.c | 2 +- drivers/crypto/ccp/sp-dev.h | 2 +- drivers/crypto/ccp/sp-pci.c | 2 +- drivers/crypto/ccp/sp-platform.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c index 9108015e56cc..f6e252c1d6fb 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c @@ -1,7 +1,7 @@ /* * AMD Cryptographic Coprocessor (CCP) AES CMAC crypto API support * - * Copyright (C) 2013 Advanced Micro Devices, Inc. + * Copyright (C) 2013,2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c index 2ca64bb57d2e..10a61cd54fce 100644 --- a/drivers/crypto/ccp/ccp-crypto-sha.c +++ b/drivers/crypto/ccp/ccp-crypto-sha.c @@ -1,7 +1,7 @@ /* * AMD Cryptographic Coprocessor (CCP) SHA crypto API support * - * Copyright (C) 2013,2017 Advanced Micro Devices, Inc. + * Copyright (C) 2013,2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * Author: Gary R Hook diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 0ea43cdeb05f..267a367bd076 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -1,7 +1,7 @@ /* * AMD Cryptographic Coprocessor (CCP) driver * - * Copyright (C) 2013,2017 Advanced Micro Devices, Inc. + * Copyright (C) 2013,2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * Author: Gary R Hook diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index b16be8a11d92..66566547feff 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -1,7 +1,7 @@ /* * AMD Platform Security Processor (PSP) interface * - * Copyright (C) 2016-2017 Advanced Micro Devices, Inc. + * Copyright (C) 2016,2018 Advanced Micro Devices, Inc. * * Author: Brijesh Singh * diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h index 8b53a9674ecb..f5afeccf42a1 100644 --- a/drivers/crypto/ccp/psp-dev.h +++ b/drivers/crypto/ccp/psp-dev.h @@ -1,7 +1,7 @@ /* * AMD Platform Security Processor (PSP) interface driver * - * Copyright (C) 2017 Advanced Micro Devices, Inc. + * Copyright (C) 2017-2018 Advanced Micro Devices, Inc. * * Author: Brijesh Singh * diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c index e0459002eb71..b2879767fc98 100644 --- a/drivers/crypto/ccp/sp-dev.c +++ b/drivers/crypto/ccp/sp-dev.c @@ -1,7 +1,7 @@ /* * AMD Secure Processor driver * - * Copyright (C) 2017 Advanced Micro Devices, Inc. + * Copyright (C) 2017-2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * Author: Gary R Hook diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 14398cad1625..5b0790025db3 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h @@ -1,7 +1,7 @@ /* * AMD Secure Processor driver * - * Copyright (C) 2017 Advanced Micro Devices, Inc. + * Copyright (C) 2017-2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * Author: Gary R Hook diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index 7da93e9bebed..6d730d3e3f6f 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -1,7 +1,7 @@ /* * AMD Secure Processor device driver * - * Copyright (C) 2013,2016 Advanced Micro Devices, Inc. + * Copyright (C) 2013,2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * Author: Gary R Hook diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c index b75dc7db2d4a..d24228efbaaa 100644 --- a/drivers/crypto/ccp/sp-platform.c +++ b/drivers/crypto/ccp/sp-platform.c @@ -1,7 +1,7 @@ /* * AMD Secure Processor device driver * - * Copyright (C) 2014,2016 Advanced Micro Devices, Inc. + * Copyright (C) 2014,2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * -- cgit v1.2.3 From 0f103b37282f48e2221aca955985550b7eabc98b Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Fri, 21 Dec 2018 17:59:08 +0200 Subject: crypto: caam - fix error reporting for caam_hash_alloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix error reporting when preparation of an hmac algorithm for registration fails: print the hmac algorithm name, not the unkeyed hash algorithm name. Signed-off-by: Iuliana Prodan Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index bb1a2cdf1951..17e86e4a6428 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -1873,7 +1873,8 @@ static int __init caam_algapi_hash_init(void) t_alg = caam_hash_alloc(alg, true); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - pr_warn("%s alg allocation failed\n", alg->driver_name); + pr_warn("%s alg allocation failed\n", + alg->hmac_driver_name); continue; } -- cgit v1.2.3 From 9a2537d0ebc984bab4f3ff5012dacf42b0ac70a2 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Fri, 21 Dec 2018 17:59:09 +0200 Subject: crypto: caam - create ahash shared descriptors only once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For keyed hash algorithms, shared descriptors are currently generated twice: -at tfm initialization time, in cra_init() callback -in setkey() callback Since it's mandatory to call setkey() for keyed algorithms, drop the generation in cra_init(). Signed-off-by: Iuliana Prodan Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 17e86e4a6428..4b88af5bea26 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -1725,7 +1725,12 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), sizeof(struct caam_hash_state)); - return ahash_set_sh_desc(ahash); + + /* + * For keyed hash algorithms shared descriptors + * will be created later in setkey() callback + */ + return alg->setkey ? 0 : ahash_set_sh_desc(ahash); } static void caam_hash_cra_exit(struct crypto_tfm *tfm) -- cgit v1.2.3 From 12b8567f6fa489c098024fc75caba2f6b1390a92 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Fri, 21 Dec 2018 17:59:10 +0200 Subject: crypto: caam - add support for xcbc(aes) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add xcbc(aes) offloading support. Due to xcbc algorithm design and HW implementation in CAAM, driver must still have some bytes to send to the crypto engine when ahash_final() is called - such that HW correctly uses either K2 or K3 for the last block. Signed-off-by: Iuliana Prodan Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 189 +++++++++++++++++++++++++++++++++--- drivers/crypto/caam/caamhash_desc.c | 58 ++++++++++- drivers/crypto/caam/caamhash_desc.h | 2 + 3 files changed, 232 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 4b88af5bea26..6c379bef938e 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -98,13 +98,14 @@ struct caam_hash_ctx { u32 sh_desc_update_first[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; u32 sh_desc_fin[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; u32 sh_desc_digest[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; + u8 key[CAAM_MAX_HASH_KEY_SIZE] ____cacheline_aligned; dma_addr_t sh_desc_update_dma ____cacheline_aligned; dma_addr_t sh_desc_update_first_dma; dma_addr_t sh_desc_fin_dma; dma_addr_t sh_desc_digest_dma; + dma_addr_t key_dma; enum dma_data_direction dir; struct device *jrdev; - u8 key[CAAM_MAX_HASH_KEY_SIZE]; int ctx_len; struct alginfo adata; }; @@ -158,6 +159,12 @@ static inline int *alt_buflen(struct caam_hash_state *state) return state->current_buf ? &state->buflen_0 : &state->buflen_1; } +static inline bool is_xcbc_aes(u32 algtype) +{ + return (algtype & (OP_ALG_ALGSEL_MASK | OP_ALG_AAI_MASK)) == + (OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC); +} + /* Common job descriptor seq in/out ptr routines */ /* Map state->caam_ctx, and append seq_out_ptr command that points to it */ @@ -292,6 +299,62 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) return 0; } +static int axcbc_set_sh_desc(struct crypto_ahash *ahash) +{ + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int digestsize = crypto_ahash_digestsize(ahash); + struct device *jrdev = ctx->jrdev; + u32 *desc; + + /* key is loaded from memory for UPDATE and FINALIZE states */ + ctx->adata.key_dma = ctx->key_dma; + + /* shared descriptor for ahash_update */ + desc = ctx->sh_desc_update; + cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len, + ctx->ctx_len, 0); + dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, + desc_bytes(desc), ctx->dir); + print_hex_dump_debug("axcbc update shdesc@" __stringify(__LINE__)" : ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + /* shared descriptor for ahash_{final,finup} */ + desc = ctx->sh_desc_fin; + cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize, + ctx->ctx_len, 0); + dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, + desc_bytes(desc), ctx->dir); + print_hex_dump_debug("axcbc finup shdesc@" __stringify(__LINE__)" : ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + /* key is immediate data for INIT and INITFINAL states */ + ctx->adata.key_virt = ctx->key; + + /* shared descriptor for first invocation of ahash_update */ + desc = ctx->sh_desc_update_first; + cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len, + ctx->ctx_len, ctx->key_dma); + dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, + desc_bytes(desc), ctx->dir); + print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__)" : ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + /* shared descriptor for ahash_digest */ + desc = ctx->sh_desc_digest; + cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize, + ctx->ctx_len, 0); + dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, + desc_bytes(desc), ctx->dir); + print_hex_dump_debug("axcbc digest shdesc@" __stringify(__LINE__)" : ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + return 0; +} + /* Digest hash size if it is too large */ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, u32 *keylen, u8 *key_out, u32 digestsize) @@ -424,6 +487,21 @@ static int ahash_setkey(struct crypto_ahash *ahash, return -EINVAL; } +static int axcbc_setkey(struct crypto_ahash *ahash, const u8 *key, + unsigned int keylen) +{ + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct device *jrdev = ctx->jrdev; + + memcpy(ctx->key, key, keylen); + dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); + ctx->adata.keylen = keylen; + + print_hex_dump_debug("axcbc ctx.key@" __stringify(__LINE__)" : ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, keylen, 1); + + return axcbc_set_sh_desc(ahash); +} /* * ahash_edesc - s/w-extended ahash descriptor * @dst_dma: physical mapped address of req->result @@ -688,6 +766,7 @@ static int ahash_update_ctx(struct ahash_request *req) u8 *buf = current_buf(state); int *buflen = current_buflen(state); u8 *next_buf = alt_buf(state); + int blocksize = crypto_ahash_blocksize(ahash); int *next_buflen = alt_buflen(state), last_buflen; int in_len = *buflen + req->nbytes, to_hash; u32 *desc; @@ -696,9 +775,19 @@ static int ahash_update_ctx(struct ahash_request *req) int ret = 0; last_buflen = *next_buflen; - *next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1); + *next_buflen = in_len & (blocksize - 1); to_hash = in_len - *next_buflen; + /* + * For XCBC, if to_hash is multiple of block size, + * keep last block in internal buffer + */ + if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize && + (*next_buflen == 0)) { + *next_buflen = blocksize; + to_hash -= blocksize; + } + if (to_hash) { src_nents = sg_nents_for_len(req->src, req->nbytes - (*next_buflen)); @@ -1122,6 +1211,7 @@ static int ahash_update_no_ctx(struct ahash_request *req) GFP_KERNEL : GFP_ATOMIC; u8 *buf = current_buf(state); int *buflen = current_buflen(state); + int blocksize = crypto_ahash_blocksize(ahash); u8 *next_buf = alt_buf(state); int *next_buflen = alt_buflen(state); int in_len = *buflen + req->nbytes, to_hash; @@ -1130,9 +1220,19 @@ static int ahash_update_no_ctx(struct ahash_request *req) u32 *desc; int ret = 0; - *next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1); + *next_buflen = in_len & (blocksize - 1); to_hash = in_len - *next_buflen; + /* + * For XCBC, if to_hash is multiple of block size, + * keep last block in internal buffer + */ + if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize && + (*next_buflen == 0)) { + *next_buflen = blocksize; + to_hash -= blocksize; + } + if (to_hash) { src_nents = sg_nents_for_len(req->src, req->nbytes - *next_buflen); @@ -1338,15 +1438,25 @@ static int ahash_update_first(struct ahash_request *req) u8 *next_buf = alt_buf(state); int *next_buflen = alt_buflen(state); int to_hash; + int blocksize = crypto_ahash_blocksize(ahash); u32 *desc; int src_nents, mapped_nents; struct ahash_edesc *edesc; int ret = 0; - *next_buflen = req->nbytes & (crypto_tfm_alg_blocksize(&ahash->base) - - 1); + *next_buflen = req->nbytes & (blocksize - 1); to_hash = req->nbytes - *next_buflen; + /* + * For XCBC, if to_hash is multiple of block size, + * keep last block in internal buffer + */ + if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize && + (*next_buflen == 0)) { + *next_buflen = blocksize; + to_hash -= blocksize; + } + if (to_hash) { src_nents = sg_nents_for_len(req->src, req->nbytes - *next_buflen); @@ -1654,6 +1764,25 @@ static struct caam_hash_template driver_hash[] = { }, }, .alg_type = OP_ALG_ALGSEL_MD5, + }, { + .hmac_name = "xcbc(aes)", + .hmac_driver_name = "xcbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, + .setkey = axcbc_setkey, + .halg = { + .digestsize = AES_BLOCK_SIZE, + .statesize = sizeof(struct caam_export_state), + }, + }, + .alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC, }, }; @@ -1695,7 +1824,28 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) } priv = dev_get_drvdata(ctx->jrdev->parent); - ctx->dir = priv->era >= 6 ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + + if (is_xcbc_aes(caam_hash->alg_type)) { + ctx->dir = DMA_TO_DEVICE; + ctx->adata.algtype = OP_TYPE_CLASS1_ALG | caam_hash->alg_type; + ctx->ctx_len = 48; + + ctx->key_dma = dma_map_single_attrs(ctx->jrdev, ctx->key, + ARRAY_SIZE(ctx->key), + DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(ctx->jrdev, ctx->key_dma)) { + dev_err(ctx->jrdev, "unable to map key\n"); + caam_jr_free(ctx->jrdev); + return -ENOMEM; + } + } else { + ctx->dir = priv->era >= 6 ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; + ctx->ctx_len = runninglen[(ctx->adata.algtype & + OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT]; + } dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_update, offsetof(struct caam_hash_ctx, @@ -1703,6 +1853,13 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); if (dma_mapping_error(ctx->jrdev, dma_addr)) { dev_err(ctx->jrdev, "unable to map shared descriptors\n"); + + if (is_xcbc_aes(caam_hash->alg_type)) + dma_unmap_single_attrs(ctx->jrdev, ctx->key_dma, + ARRAY_SIZE(ctx->key), + DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); + caam_jr_free(ctx->jrdev); return -ENOMEM; } @@ -1716,13 +1873,6 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) ctx->sh_desc_digest_dma = dma_addr + offsetof(struct caam_hash_ctx, sh_desc_digest); - /* copy descriptor header template value */ - ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; - - ctx->ctx_len = runninglen[(ctx->adata.algtype & - OP_ALG_ALGSEL_SUBMASK) >> - OP_ALG_ALGSEL_SHIFT]; - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), sizeof(struct caam_hash_state)); @@ -1738,9 +1888,12 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm) struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_update_dma, - offsetof(struct caam_hash_ctx, - sh_desc_update_dma), + offsetof(struct caam_hash_ctx, key), ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); + if (is_xcbc_aes(ctx->adata.algtype)) + dma_unmap_single_attrs(ctx->jrdev, ctx->key_dma, + ARRAY_SIZE(ctx->key), DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); caam_jr_free(ctx->jrdev); } @@ -1871,7 +2024,8 @@ static int __init caam_algapi_hash_init(void) struct caam_hash_template *alg = driver_hash + i; /* If MD size is not supported by device, skip registration */ - if (alg->template_ahash.halg.digestsize > md_limit) + if (is_mdha(alg->alg_type) && + alg->template_ahash.halg.digestsize > md_limit) continue; /* register hmac version */ @@ -1892,6 +2046,9 @@ static int __init caam_algapi_hash_init(void) } else list_add_tail(&t_alg->entry, &hash_list); + if ((alg->alg_type & OP_ALG_ALGSEL_MASK) == OP_ALG_ALGSEL_AES) + continue; + /* register unkeyed version */ t_alg = caam_hash_alloc(alg, false); if (IS_ERR(t_alg)) { diff --git a/drivers/crypto/caam/caamhash_desc.c b/drivers/crypto/caam/caamhash_desc.c index a12f7959a2c3..053d3a15ef3c 100644 --- a/drivers/crypto/caam/caamhash_desc.c +++ b/drivers/crypto/caam/caamhash_desc.c @@ -2,7 +2,7 @@ /* * Shared descriptors for ahash algorithms * - * Copyright 2017 NXP + * Copyright 2017-2018 NXP */ #include "compat.h" @@ -75,6 +75,62 @@ void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state, } EXPORT_SYMBOL(cnstr_shdsc_ahash); +/** + * cnstr_shdsc_axcbc - axcbc shared descriptor + * @desc: pointer to buffer used for descriptor construction + * @adata: pointer to authentication transform definitions. + * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE} + * @digestsize: algorithm's digest size + * @ctx_len: size of Context Register + * @key_dma: I/O Virtual Address of the key + */ +void cnstr_shdsc_axcbc(u32 * const desc, struct alginfo *adata, u32 state, + int digestsize, int ctx_len, dma_addr_t key_dma) +{ + u32 *skip_key_load; + + init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + + /* Skip loading of key, context if already shared */ + skip_key_load = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); + + if (state == OP_ALG_AS_INIT || state == OP_ALG_AS_INITFINAL) { + append_key_as_imm(desc, adata->key_virt, adata->keylen, + adata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + } else { /* UPDATE, FINALIZE */ + /* Load K1 */ + append_key(desc, adata->key_dma, adata->keylen, + CLASS_1 | KEY_DEST_CLASS_REG | KEY_ENC); + /* Restore context */ + append_seq_load(desc, ctx_len, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT); + } + + set_jump_tgt_here(desc, skip_key_load); + + /* Class 1 operation */ + append_operation(desc, adata->algtype | state | OP_ALG_ENCRYPT); + + /* + * Load from buf and/or src and write to req->result or state->context + * Calculate remaining bytes to read + */ + append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* Read remaining bytes */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_LAST1 | + FIFOLD_TYPE_MSG | FIFOLDST_VLF); + + /* Save context (partial hash, K2, K3) */ + append_seq_store(desc, digestsize, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT); + if (state == OP_ALG_AS_INIT) + /* Save K1 */ + append_fifo_store(desc, key_dma, adata->keylen, + LDST_CLASS_1_CCB | FIFOST_TYPE_KEY_KEK); +} +EXPORT_SYMBOL(cnstr_shdsc_axcbc); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("FSL CAAM ahash descriptors support"); MODULE_AUTHOR("NXP Semiconductors"); diff --git a/drivers/crypto/caam/caamhash_desc.h b/drivers/crypto/caam/caamhash_desc.h index 631fc1ac312c..cf4a437d4c02 100644 --- a/drivers/crypto/caam/caamhash_desc.h +++ b/drivers/crypto/caam/caamhash_desc.h @@ -18,4 +18,6 @@ void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state, int digestsize, int ctx_len, bool import_ctx, int era); +void cnstr_shdsc_axcbc(u32 * const desc, struct alginfo *adata, u32 state, + int digestsize, int ctx_len, dma_addr_t key_dma); #endif /* _CAAMHASH_DESC_H_ */ -- cgit v1.2.3 From d072bfa4885354fff86aa1fb1dbc4f1533c9e0bf Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 23 Dec 2018 02:16:13 +0100 Subject: crypto: crypto4xx - add prng crypto support This patch adds support for crypto4xx's ANSI X9.17 Annex C compliant pseudo random number generator which provides a pseudo random source for the purpose of generating Initialization Vectors (IV's) for AES algorithms to the Packet Engine and other pseudo random number requirements. Signed-off-by: Christian Lamparter Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_core.c | 87 +++++++++++++++++++++++++++++++++ drivers/crypto/amcc/crypto4xx_core.h | 4 ++ drivers/crypto/amcc/crypto4xx_reg_def.h | 1 + 3 files changed, 92 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 63cb6956c948..f869e8cc4e0b 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -40,9 +40,11 @@ #include #include #include +#include #include #include #include +#include #include #include "crypto4xx_reg_def.h" #include "crypto4xx_core.h" @@ -1035,6 +1037,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, rc = crypto_register_ahash(&alg->alg.u.hash); break; + case CRYPTO_ALG_TYPE_RNG: + rc = crypto_register_rng(&alg->alg.u.rng); + break; + default: rc = crypto_register_skcipher(&alg->alg.u.cipher); break; @@ -1064,6 +1070,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev) crypto_unregister_aead(&alg->alg.u.aead); break; + case CRYPTO_ALG_TYPE_RNG: + crypto_unregister_rng(&alg->alg.u.rng); + break; + default: crypto_unregister_skcipher(&alg->alg.u.cipher); } @@ -1122,6 +1132,69 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data) PPC4XX_TMO_ERR_INT); } +static int ppc4xx_prng_data_read(struct crypto4xx_device *dev, + u8 *data, unsigned int max) +{ + unsigned int i, curr = 0; + u32 val[2]; + + do { + /* trigger PRN generation */ + writel(PPC4XX_PRNG_CTRL_AUTO_EN, + dev->ce_base + CRYPTO4XX_PRNG_CTRL); + + for (i = 0; i < 1024; i++) { + /* usually 19 iterations are enough */ + if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) & + CRYPTO4XX_PRNG_STAT_BUSY)) + continue; + + val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0); + val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1); + break; + } + if (i == 1024) + return -ETIMEDOUT; + + if ((max - curr) >= 8) { + memcpy(data, &val, 8); + data += 8; + curr += 8; + } else { + /* copy only remaining bytes */ + memcpy(data, &val, max - curr); + break; + } + } while (curr < max); + + return curr; +} + +static int crypto4xx_prng_generate(struct crypto_rng *tfm, + const u8 *src, unsigned int slen, + u8 *dstn, unsigned int dlen) +{ + struct rng_alg *alg = crypto_rng_alg(tfm); + struct crypto4xx_alg *amcc_alg; + struct crypto4xx_device *dev; + int ret; + + amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng); + dev = amcc_alg->dev; + + mutex_lock(&dev->core_dev->rng_lock); + ret = ppc4xx_prng_data_read(dev, dstn, dlen); + mutex_unlock(&dev->core_dev->rng_lock); + return ret; +} + + +static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed, + unsigned int slen) +{ + return 0; +} + /** * Supported Crypto Algorithms */ @@ -1291,6 +1364,18 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .cra_module = THIS_MODULE, }, } }, + { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = { + .base = { + .cra_name = "stdrng", + .cra_driver_name = "crypto4xx_rng", + .cra_priority = 300, + .cra_ctxsize = 0, + .cra_module = THIS_MODULE, + }, + .generate = crypto4xx_prng_generate, + .seed = crypto4xx_prng_seed, + .seedsize = 0, + } }, }; /** @@ -1360,6 +1445,7 @@ static int crypto4xx_probe(struct platform_device *ofdev) core_dev->dev->core_dev = core_dev; core_dev->dev->is_revb = is_revb; core_dev->device = dev; + mutex_init(&core_dev->rng_lock); spin_lock_init(&core_dev->lock); INIT_LIST_HEAD(&core_dev->dev->alg_list); ratelimit_default_init(&core_dev->dev->aead_ratelimit); @@ -1439,6 +1525,7 @@ static int crypto4xx_remove(struct platform_device *ofdev) tasklet_kill(&core_dev->tasklet); /* Un-register with Linux CryptoAPI */ crypto4xx_unregister_alg(core_dev->dev); + mutex_destroy(&core_dev->rng_lock); /* Free all allocated memory */ crypto4xx_stop_all(core_dev); diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index e2ca56722f07..18df695ca6b1 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -23,8 +23,10 @@ #define __CRYPTO4XX_CORE_H__ #include +#include #include #include +#include #include #include "crypto4xx_reg_def.h" #include "crypto4xx_sa.h" @@ -119,6 +121,7 @@ struct crypto4xx_core_device { u32 irq; struct tasklet_struct tasklet; spinlock_t lock; + struct mutex rng_lock; }; struct crypto4xx_ctx { @@ -143,6 +146,7 @@ struct crypto4xx_alg_common { struct skcipher_alg cipher; struct ahash_alg hash; struct aead_alg aead; + struct rng_alg rng; } u; }; diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h index 472331787e04..80c67490bbf6 100644 --- a/drivers/crypto/amcc/crypto4xx_reg_def.h +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h @@ -100,6 +100,7 @@ #define CRYPTO4XX_ENDIAN_CFG 0x000600d8 #define CRYPTO4XX_PRNG_STAT 0x00070000 +#define CRYPTO4XX_PRNG_STAT_BUSY 0x1 #define CRYPTO4XX_PRNG_CTRL 0x00070004 #define CRYPTO4XX_PRNG_SEED_L 0x00070008 #define CRYPTO4XX_PRNG_SEED_H 0x0007000c -- cgit v1.2.3 From be8a54d367bfef7a5b354975f878441383ce9993 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 28 Dec 2018 06:10:33 +0000 Subject: crypto: ux500 - catch dma submission error Test cookie return by dmaengine_submit() and return error if any. Signed-off-by: YueHaibing Signed-off-by: Herbert Xu --- drivers/crypto/ux500/cryp/cryp_core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c index a92a66b1ff46..db94f89d8d11 100644 --- a/drivers/crypto/ux500/cryp/cryp_core.c +++ b/drivers/crypto/ux500/cryp/cryp_core.c @@ -595,6 +595,12 @@ static int cryp_set_dma_transfer(struct cryp_ctx *ctx, } cookie = dmaengine_submit(desc); + if (dma_submit_error(cookie)) { + dev_dbg(ctx->device->dev, "[%s]: DMA submission failed\n", + __func__); + return cookie; + } + dma_async_issue_pending(channel); return 0; -- cgit v1.2.3 From 66af86d93ce32ff5b262ace9a6696873cc1bdb3e Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 28 Dec 2018 14:41:00 +0800 Subject: crypto: chelsio - check set_msg_len overflow in generate_b0 set_msg_len may fails with -EOVERFLOW, It should be propagate to upstream. Fixes: 2debd3325e55 ("crypto: chcr - Add AEAD algos.") Signed-off-by: YueHaibing Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index bcef76508dfa..bdbdce9fdf25 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -2762,7 +2762,7 @@ static int set_msg_len(u8 *block, unsigned int msglen, int csize) return 0; } -static void generate_b0(struct aead_request *req, u8 *ivptr, +static int generate_b0(struct aead_request *req, u8 *ivptr, unsigned short op_type) { unsigned int l, lp, m; @@ -2787,6 +2787,8 @@ static void generate_b0(struct aead_request *req, u8 *ivptr, rc = set_msg_len(b0 + 16 - l, (op_type == CHCR_DECRYPT_OP) ? req->cryptlen - m : req->cryptlen, l); + + return rc; } static inline int crypto_ccm_check_iv(const u8 *iv) @@ -2821,7 +2823,7 @@ static int ccm_format_packet(struct aead_request *req, *((unsigned short *)(reqctx->scratch_pad + 16)) = htons(assoclen); - generate_b0(req, ivptr, op_type); + rc = generate_b0(req, ivptr, op_type); /* zero the ctr value */ memset(ivptr + 15 - ivptr[0], 0, ivptr[0] + 1); return rc; -- cgit v1.2.3 From e12468241b19653d87534f3ff0778f1ad4668f5e Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 28 Dec 2018 06:53:53 +0000 Subject: crypto: chelsio - remove set but not used variables 'adap' Fixes gcc '-Wunused-but-set-variable' warning: drivers/crypto/chelsio/chcr_algo.c: In function 'chcr_device_init': drivers/crypto/chelsio/chcr_algo.c:1371:18: warning: variable 'adap' set but not used [-Wunused-but-set-variable] It not used since commit a1c6fd4308d3 ("crypto: chelsio - Update ntx queue received from cxgb4") Signed-off-by: YueHaibing Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index bdbdce9fdf25..adc1b3069d60 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -1368,7 +1368,6 @@ static int chcr_aes_decrypt(struct ablkcipher_request *req) static int chcr_device_init(struct chcr_context *ctx) { struct uld_ctx *u_ctx = NULL; - struct adapter *adap; unsigned int id; int txq_perchan, txq_idx, ntxq; int err = 0, rxq_perchan, rxq_idx; @@ -1382,7 +1381,6 @@ static int chcr_device_init(struct chcr_context *ctx) goto out; } ctx->dev = &u_ctx->dev; - adap = padap(ctx->dev); ntxq = u_ctx->lldi.ntxq; rxq_perchan = u_ctx->lldi.nrxq / u_ctx->lldi.nchan; txq_perchan = ntxq / u_ctx->lldi.nchan; -- cgit v1.2.3 From 1bb64d867cfe84cc3c255d8fdeff0b4d86341519 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 30 Dec 2018 13:46:21 +0000 Subject: crypto: virtio - clean up indentation, replace spaces with tab A statement is indented with spaces and not indented enough, fix this replacing spaces with a tab. Signed-off-by: Colin Ian King Signed-off-by: Herbert Xu --- drivers/crypto/virtio/virtio_crypto_algs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c index 2c573d1aaa64..0704833ece92 100644 --- a/drivers/crypto/virtio/virtio_crypto_algs.c +++ b/drivers/crypto/virtio/virtio_crypto_algs.c @@ -406,7 +406,7 @@ __virtio_crypto_ablkcipher_do_req(struct virtio_crypto_sym_request *vc_sym_req, } else { req_data->header.session_id = cpu_to_le64(ctx->dec_sess_info.session_id); - req_data->header.opcode = + req_data->header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DECRYPT); } req_data->u.sym_req.op_type = cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); -- cgit v1.2.3 From b798d5a1b0eaf276f463262284e58a29b451063c Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 17 Dec 2018 16:31:51 +0100 Subject: soc: imx: gpcv2: handle additional power-down bits in handshake register Some of the i.MX8MQ domains have an additional control bit in the PU handshake (HSK) register. Documentation about this bit is a bit sparse at the moment, but it seems that it controls a power-down request to the AMBA domain bridge (ADB-400) attached to those domains. As the documentation doesn't desribe the usage of this bit yet, handle it in the same way as done in the ATF implementation. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 8b4f48a2ca57..a8dd0cddb3d2 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -65,6 +65,12 @@ #define GPC_M4_PU_PDN_FLG 0x1bc +#define GPC_PU_PWRHSK 0x1fc + +#define IMX8M_GPU_HSK_PWRDNREQN BIT(6) +#define IMX8M_VPU_HSK_PWRDNREQN BIT(5) +#define IMX8M_DISP_HSK_PWRDNREQN BIT(4) + /* * The PGC offset values in Reference Manual * (Rev. 1, 01/2018 and the older ones) GPC chapter's @@ -102,6 +108,7 @@ struct imx_pgc_domain { const struct { u32 pxx; u32 map; + u32 hsk; } bits; const int voltage; @@ -142,6 +149,10 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); + if (domain->bits.hsk) + regmap_update_bits(domain->regmap, GPC_PU_PWRHSK, + domain->bits.hsk, on ? domain->bits.hsk : 0); + regmap_update_bits(domain->regmap, offset, domain->bits.pxx, domain->bits.pxx); @@ -328,6 +339,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_GPU_SW_Pxx_REQ, .map = IMX8M_GPU_A53_DOMAIN, + .hsk = IMX8M_GPU_HSK_PWRDNREQN, }, .pgc = IMX8M_PGC_GPU, }, @@ -339,6 +351,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_VPU_SW_Pxx_REQ, .map = IMX8M_VPU_A53_DOMAIN, + .hsk = IMX8M_VPU_HSK_PWRDNREQN, }, .pgc = IMX8M_PGC_VPU, }, @@ -350,6 +363,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_DISP_SW_Pxx_REQ, .map = IMX8M_DISP_A53_DOMAIN, + .hsk = IMX8M_DISP_HSK_PWRDNREQN, }, .pgc = IMX8M_PGC_DISP, }, @@ -390,7 +404,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { static const struct regmap_range imx8m_yes_ranges[] = { regmap_reg_range(GPC_LPCR_A_CORE_BSC, - GPC_M4_PU_PDN_FLG), + GPC_PU_PWRHSK), regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI), GPC_PGC_SR(IMX8M_PGC_MIPI)), regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE1), -- cgit v1.2.3 From ae1d2add26a4a0d34dc0615d304be2f341202e77 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 17 Dec 2018 16:31:52 +0100 Subject: soc: imx: gpcv2: handle reset clocks Some power domains handled by the GPCv2 driver need to enable the clocks for devies inside the domain, so that the reset propagation and proper power-up sequencing happens. Handle them in the same way as on GPCv1. Signed-off-by: Lucas Stach Acked-by: Rob Herring Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index a8dd0cddb3d2..176f473127b6 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -8,6 +8,7 @@ * Copyright 2015-2017 Pengutronix, Lucas Stach */ +#include #include #include #include @@ -98,10 +99,14 @@ #define GPC_PGC_CTRL_PCR BIT(0) +#define GPC_CLK_MAX 6 + struct imx_pgc_domain { struct generic_pm_domain genpd; struct regmap *regmap; struct regulator *regulator; + struct clk *clk[GPC_CLK_MAX]; + int num_clks; unsigned int pgc; @@ -132,7 +137,7 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, const bool enable_power_control = !on; const bool has_regulator = !IS_ERR(domain->regulator); unsigned long deadline; - int ret = 0; + int i, ret = 0; regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, domain->bits.map, domain->bits.map); @@ -145,6 +150,10 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, } } + /* Enable reset clocks for all devices in the domain */ + for (i = 0; i < domain->num_clks; i++) + clk_prepare_enable(domain->clk[i]); + if (enable_power_control) regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); @@ -190,6 +199,10 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), GPC_PGC_CTRL_PCR, 0); + /* Disable reset clocks for all devices in the domain */ + for (i = 0; i < domain->num_clks; i++) + clk_disable_unprepare(domain->clk[i]); + if (has_regulator && !on) { int err; @@ -440,6 +453,41 @@ static const struct imx_pgc_domain_data imx8m_pgc_domain_data = { .reg_access_table = &imx8m_access_table, }; +static int imx_pgc_get_clocks(struct imx_pgc_domain *domain) +{ + int i, ret; + + for (i = 0; ; i++) { + struct clk *clk = of_clk_get(domain->dev->of_node, i); + if (IS_ERR(clk)) + break; + if (i >= GPC_CLK_MAX) { + dev_err(domain->dev, "more than %d clocks\n", + GPC_CLK_MAX); + ret = -EINVAL; + goto clk_err; + } + domain->clk[i] = clk; + } + domain->num_clks = i; + + return 0; + +clk_err: + while (i--) + clk_put(domain->clk[i]); + + return ret; +} + +static void imx_pgc_put_clocks(struct imx_pgc_domain *domain) +{ + int i; + + for (i = domain->num_clks - 1; i >= 0; i--) + clk_put(domain->clk[i]); +} + static int imx_pgc_domain_probe(struct platform_device *pdev) { struct imx_pgc_domain *domain = pdev->dev.platform_data; @@ -459,9 +507,17 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) domain->voltage, domain->voltage); } + ret = imx_pgc_get_clocks(domain); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(domain->dev, "Failed to get domain's clocks\n"); + return ret; + } + ret = pm_genpd_init(&domain->genpd, NULL, true); if (ret) { dev_err(domain->dev, "Failed to init power domain\n"); + imx_pgc_put_clocks(domain); return ret; } @@ -470,6 +526,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) if (ret) { dev_err(domain->dev, "Failed to add genpd provider\n"); pm_genpd_remove(&domain->genpd); + imx_pgc_put_clocks(domain); } return ret; @@ -481,6 +538,7 @@ static int imx_pgc_domain_remove(struct platform_device *pdev) of_genpd_del_provider(domain->dev->of_node); pm_genpd_remove(&domain->genpd); + imx_pgc_put_clocks(domain); return 0; } -- cgit v1.2.3 From 8b8cb52af34da2faa293614b2554c8eac30faeaa Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Mon, 17 Dec 2018 10:47:59 -0500 Subject: bus: imx-weim: support multiple address ranges per child node Ensure that timing values for the child node are applied to all chip selects in the child's address ranges. Note that this does not support multiple timing settings per child; this can be added in the future if required. Example: &weim { acme@0 { compatible = "acme,whatever"; reg = <0 0 0x100>, <0 0x400000 0x800>, <1 0x400000 0x800>; fsl,weim-cs-timing = <0x024400b1 0x00001010 0x20081100 0x00000000 0xa0000240 0x00000000>; }; }; Signed-off-by: Sven Van Asbroeck Signed-off-by: Shawn Guo --- drivers/bus/imx-weim.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index d84996a4528e..1a0e0277a404 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -46,6 +46,7 @@ static const struct imx_weim_devtype imx51_weim_devtype = { }; #define MAX_CS_REGS_COUNT 6 +#define OF_REG_SIZE 3 static const struct of_device_id weim_id_table[] = { /* i.MX1/21 */ @@ -116,26 +117,40 @@ static int __init weim_timing_setup(struct device_node *np, void __iomem *base, { u32 cs_idx, value[MAX_CS_REGS_COUNT]; int i, ret; + int reg_idx, num_regs; if (WARN_ON(devtype->cs_regs_count > MAX_CS_REGS_COUNT)) return -EINVAL; - /* get the CS index from this child node's "reg" property. */ - ret = of_property_read_u32(np, "reg", &cs_idx); + ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", + value, devtype->cs_regs_count); if (ret) return ret; - if (cs_idx >= devtype->cs_count) + /* + * the child node's "reg" property may contain multiple address ranges, + * extract the chip select for each. + */ + num_regs = of_property_count_elems_of_size(np, "reg", OF_REG_SIZE); + if (num_regs < 0) + return num_regs; + if (!num_regs) return -EINVAL; + for (reg_idx = 0; reg_idx < num_regs; reg_idx++) { + /* get the CS index from this child node's "reg" property. */ + ret = of_property_read_u32_index(np, "reg", + reg_idx * OF_REG_SIZE, &cs_idx); + if (ret) + break; - ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", - value, devtype->cs_regs_count); - if (ret) - return ret; + if (cs_idx >= devtype->cs_count) + return -EINVAL; - /* set the timing for WEIM */ - for (i = 0; i < devtype->cs_regs_count; i++) - writel(value[i], base + cs_idx * devtype->cs_stride + i * 4); + /* set the timing for WEIM */ + for (i = 0; i < devtype->cs_regs_count; i++) + writel(value[i], + base + cs_idx * devtype->cs_stride + i * 4); + } return 0; } -- cgit v1.2.3 From c7995bcb36ef61e8b4136efab31ecf3c9b1633f9 Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Mon, 17 Dec 2018 10:48:00 -0500 Subject: bus: imx-weim: guard against timing configuration conflicts When specifying weim child devices, there is a risk that more than one timing setting is specified for the same chip select. The driver cannot support such a configuration. In case of conflict, this patch will print a warning to the log, and will ignore the child node in question. In this example, node acme@1 will be ignored, as it tries to modify timing settings for CS0: &weim { acme@0 { compatible = "acme,whatever"; reg = <0 0 0x100>; fsl,weim-cs-timing = ; }; acme@1 { compatible = "acme,whatnot"; reg = <0 0x500 0x100>; fsl,weim-cs-timing = ; }; }; However in this example, the driver will be happy: &weim { acme@0 { compatible = "acme,whatever"; reg = <0 0 0x100>; fsl,weim-cs-timing = ; }; acme@1 { compatible = "acme,whatnot"; reg = <0 0x500 0x100>; fsl,weim-cs-timing = ; }; }; Signed-off-by: Sven Van Asbroeck Signed-off-by: Shawn Guo --- drivers/bus/imx-weim.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index 1a0e0277a404..db74334ca5ef 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -46,8 +46,18 @@ static const struct imx_weim_devtype imx51_weim_devtype = { }; #define MAX_CS_REGS_COUNT 6 +#define MAX_CS_COUNT 6 #define OF_REG_SIZE 3 +struct cs_timing { + bool is_applied; + u32 regs[MAX_CS_REGS_COUNT]; +}; + +struct cs_timing_state { + struct cs_timing cs[MAX_CS_COUNT]; +}; + static const struct of_device_id weim_id_table[] = { /* i.MX1/21 */ { .compatible = "fsl,imx1-weim", .data = &imx1_weim_devtype, }, @@ -112,15 +122,20 @@ err: } /* Parse and set the timing for this device. */ -static int __init weim_timing_setup(struct device_node *np, void __iomem *base, - const struct imx_weim_devtype *devtype) +static int __init weim_timing_setup(struct device *dev, + struct device_node *np, void __iomem *base, + const struct imx_weim_devtype *devtype, + struct cs_timing_state *ts) { u32 cs_idx, value[MAX_CS_REGS_COUNT]; int i, ret; int reg_idx, num_regs; + struct cs_timing *cst; if (WARN_ON(devtype->cs_regs_count > MAX_CS_REGS_COUNT)) return -EINVAL; + if (WARN_ON(devtype->cs_count > MAX_CS_COUNT)) + return -EINVAL; ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", value, devtype->cs_regs_count); @@ -146,10 +161,23 @@ static int __init weim_timing_setup(struct device_node *np, void __iomem *base, if (cs_idx >= devtype->cs_count) return -EINVAL; + /* prevent re-configuring a CS that's already been configured */ + cst = &ts->cs[cs_idx]; + if (cst->is_applied && memcmp(value, cst->regs, + devtype->cs_regs_count * sizeof(u32))) { + dev_err(dev, "fsl,weim-cs-timing conflict on %pOF", np); + return -EINVAL; + } + /* set the timing for WEIM */ for (i = 0; i < devtype->cs_regs_count; i++) writel(value[i], base + cs_idx * devtype->cs_stride + i * 4); + if (!cst->is_applied) { + cst->is_applied = true; + memcpy(cst->regs, value, + devtype->cs_regs_count * sizeof(u32)); + } } return 0; @@ -163,6 +191,7 @@ static int __init weim_parse_dt(struct platform_device *pdev, const struct imx_weim_devtype *devtype = of_id->data; struct device_node *child; int ret, have_child = 0; + struct cs_timing_state ts = {}; if (devtype == &imx50_weim_devtype) { ret = imx_weim_gpr_setup(pdev); @@ -171,7 +200,7 @@ static int __init weim_parse_dt(struct platform_device *pdev, } for_each_available_child_of_node(pdev->dev.of_node, child) { - ret = weim_timing_setup(child, base, devtype); + ret = weim_timing_setup(&pdev->dev, child, base, devtype, &ts); if (ret) dev_warn(&pdev->dev, "%pOF set timing failed.\n", child); -- cgit v1.2.3 From f05c07b05d67c578d2f11c04482d983dba7ebc9c Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Tue, 18 Dec 2018 15:22:58 +0000 Subject: pinctrl: imx: add imx8qm driver MX8QM contains a system controller that is responsible for controlling the pad setting of the IPs that are present. Communication between the host processor running an OS and the system controller happens through a SCU protocol. This patch adds the SCU based MX8QM pinctrl driver. Cc: Linus Walleij Cc: Shawn Guo Cc: Fabio Estevam Cc: Stefan Agner Signed-off-by: Dong Aisheng Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx8qm.c | 326 +++++++++++++++++++++++++++++ 3 files changed, 334 insertions(+) create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8qm.c (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 72b869d888e2..b318c24b61be 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -129,6 +129,13 @@ config PINCTRL_IMX8MQ help Say Y here to enable the imx8mq pinctrl driver +config PINCTRL_IMX8QM + bool "IMX8QM pinctrl driver" + depends on ARCH_MXC && ARM64 + select PINCTRL_IMX_SCU + help + Say Y here to enable the imx8qm pinctrl driver + config PINCTRL_IMX8QXP bool "IMX8QXP pinctrl driver" depends on ARCH_MXC && ARM64 diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 6ee398a3e406..a6783f2560ae 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o obj-$(CONFIG_PINCTRL_IMX7D) += pinctrl-imx7d.o obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o obj-$(CONFIG_PINCTRL_IMX8MQ) += pinctrl-imx8mq.o +obj-$(CONFIG_PINCTRL_IMX8QM) += pinctrl-imx8qm.o obj-$(CONFIG_PINCTRL_IMX8QXP) += pinctrl-imx8qxp.o obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx8qm.c b/drivers/pinctrl/freescale/pinctrl-imx8qm.c new file mode 100644 index 000000000000..0b6029b29731 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx8qm.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * Dong Aisheng + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +static const struct pinctrl_pin_desc imx8qm_pinctrl_pads[] = { + IMX_PINCTRL_PIN(IMX8QM_SIM0_CLK), + IMX_PINCTRL_PIN(IMX8QM_SIM0_RST), + IMX_PINCTRL_PIN(IMX8QM_SIM0_IO), + IMX_PINCTRL_PIN(IMX8QM_SIM0_PD), + IMX_PINCTRL_PIN(IMX8QM_SIM0_POWER_EN), + IMX_PINCTRL_PIN(IMX8QM_SIM0_GPIO0_00), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_SIM), + IMX_PINCTRL_PIN(IMX8QM_M40_I2C0_SCL), + IMX_PINCTRL_PIN(IMX8QM_M40_I2C0_SDA), + IMX_PINCTRL_PIN(IMX8QM_M40_GPIO0_00), + IMX_PINCTRL_PIN(IMX8QM_M40_GPIO0_01), + IMX_PINCTRL_PIN(IMX8QM_M41_I2C0_SCL), + IMX_PINCTRL_PIN(IMX8QM_M41_I2C0_SDA), + IMX_PINCTRL_PIN(IMX8QM_M41_GPIO0_00), + IMX_PINCTRL_PIN(IMX8QM_M41_GPIO0_01), + IMX_PINCTRL_PIN(IMX8QM_GPT0_CLK), + IMX_PINCTRL_PIN(IMX8QM_GPT0_CAPTURE), + IMX_PINCTRL_PIN(IMX8QM_GPT0_COMPARE), + IMX_PINCTRL_PIN(IMX8QM_GPT1_CLK), + IMX_PINCTRL_PIN(IMX8QM_GPT1_CAPTURE), + IMX_PINCTRL_PIN(IMX8QM_GPT1_COMPARE), + IMX_PINCTRL_PIN(IMX8QM_UART0_RX), + IMX_PINCTRL_PIN(IMX8QM_UART0_TX), + IMX_PINCTRL_PIN(IMX8QM_UART0_RTS_B), + IMX_PINCTRL_PIN(IMX8QM_UART0_CTS_B), + IMX_PINCTRL_PIN(IMX8QM_UART1_TX), + IMX_PINCTRL_PIN(IMX8QM_UART1_RX), + IMX_PINCTRL_PIN(IMX8QM_UART1_RTS_B), + IMX_PINCTRL_PIN(IMX8QM_UART1_CTS_B), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_GPIOLH), + IMX_PINCTRL_PIN(IMX8QM_SCU_PMIC_MEMC_ON), + IMX_PINCTRL_PIN(IMX8QM_SCU_WDOG_OUT), + IMX_PINCTRL_PIN(IMX8QM_PMIC_I2C_SDA), + IMX_PINCTRL_PIN(IMX8QM_PMIC_I2C_SCL), + IMX_PINCTRL_PIN(IMX8QM_PMIC_EARLY_WARNING), + IMX_PINCTRL_PIN(IMX8QM_PMIC_INT_B), + IMX_PINCTRL_PIN(IMX8QM_SCU_GPIO0_00), + IMX_PINCTRL_PIN(IMX8QM_SCU_GPIO0_01), + IMX_PINCTRL_PIN(IMX8QM_SCU_GPIO0_02), + IMX_PINCTRL_PIN(IMX8QM_SCU_GPIO0_03), + IMX_PINCTRL_PIN(IMX8QM_SCU_GPIO0_04), + IMX_PINCTRL_PIN(IMX8QM_SCU_GPIO0_05), + IMX_PINCTRL_PIN(IMX8QM_SCU_GPIO0_06), + IMX_PINCTRL_PIN(IMX8QM_SCU_GPIO0_07), + IMX_PINCTRL_PIN(IMX8QM_SCU_BOOT_MODE0), + IMX_PINCTRL_PIN(IMX8QM_SCU_BOOT_MODE1), + IMX_PINCTRL_PIN(IMX8QM_SCU_BOOT_MODE2), + IMX_PINCTRL_PIN(IMX8QM_SCU_BOOT_MODE3), + IMX_PINCTRL_PIN(IMX8QM_SCU_BOOT_MODE4), + IMX_PINCTRL_PIN(IMX8QM_SCU_BOOT_MODE5), + IMX_PINCTRL_PIN(IMX8QM_LVDS0_GPIO00), + IMX_PINCTRL_PIN(IMX8QM_LVDS0_GPIO01), + IMX_PINCTRL_PIN(IMX8QM_LVDS0_I2C0_SCL), + IMX_PINCTRL_PIN(IMX8QM_LVDS0_I2C0_SDA), + IMX_PINCTRL_PIN(IMX8QM_LVDS0_I2C1_SCL), + IMX_PINCTRL_PIN(IMX8QM_LVDS0_I2C1_SDA), + IMX_PINCTRL_PIN(IMX8QM_LVDS1_GPIO00), + IMX_PINCTRL_PIN(IMX8QM_LVDS1_GPIO01), + IMX_PINCTRL_PIN(IMX8QM_LVDS1_I2C0_SCL), + IMX_PINCTRL_PIN(IMX8QM_LVDS1_I2C0_SDA), + IMX_PINCTRL_PIN(IMX8QM_LVDS1_I2C1_SCL), + IMX_PINCTRL_PIN(IMX8QM_LVDS1_I2C1_SDA), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_LVDSGPIO), + IMX_PINCTRL_PIN(IMX8QM_MIPI_DSI0_I2C0_SCL), + IMX_PINCTRL_PIN(IMX8QM_MIPI_DSI0_I2C0_SDA), + IMX_PINCTRL_PIN(IMX8QM_MIPI_DSI0_GPIO0_00), + IMX_PINCTRL_PIN(IMX8QM_MIPI_DSI0_GPIO0_01), + IMX_PINCTRL_PIN(IMX8QM_MIPI_DSI1_I2C0_SCL), + IMX_PINCTRL_PIN(IMX8QM_MIPI_DSI1_I2C0_SDA), + IMX_PINCTRL_PIN(IMX8QM_MIPI_DSI1_GPIO0_00), + IMX_PINCTRL_PIN(IMX8QM_MIPI_DSI1_GPIO0_01), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_MIPIDSIGPIO), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI0_MCLK_OUT), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI0_I2C0_SCL), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI0_I2C0_SDA), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI0_GPIO0_00), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI0_GPIO0_01), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI1_MCLK_OUT), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI1_GPIO0_00), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI1_GPIO0_01), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI1_I2C0_SCL), + IMX_PINCTRL_PIN(IMX8QM_MIPI_CSI1_I2C0_SDA), + IMX_PINCTRL_PIN(IMX8QM_HDMI_TX0_TS_SCL), + IMX_PINCTRL_PIN(IMX8QM_HDMI_TX0_TS_SDA), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_3V3_HDMIGPIO), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_FSR), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_FST), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_SCKR), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_SCKT), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_TX0), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_TX1), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_TX2_RX3), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_TX3_RX2), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_TX4_RX1), + IMX_PINCTRL_PIN(IMX8QM_ESAI1_TX5_RX0), + IMX_PINCTRL_PIN(IMX8QM_SPDIF0_RX), + IMX_PINCTRL_PIN(IMX8QM_SPDIF0_TX), + IMX_PINCTRL_PIN(IMX8QM_SPDIF0_EXT_CLK), + IMX_PINCTRL_PIN(IMX8QM_SPI3_SCK), + IMX_PINCTRL_PIN(IMX8QM_SPI3_SDO), + IMX_PINCTRL_PIN(IMX8QM_SPI3_SDI), + IMX_PINCTRL_PIN(IMX8QM_SPI3_CS0), + IMX_PINCTRL_PIN(IMX8QM_SPI3_CS1), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_GPIORHB), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_FSR), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_FST), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_SCKR), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_SCKT), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_TX0), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_TX1), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_TX2_RX3), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_TX3_RX2), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_TX4_RX1), + IMX_PINCTRL_PIN(IMX8QM_ESAI0_TX5_RX0), + IMX_PINCTRL_PIN(IMX8QM_MCLK_IN0), + IMX_PINCTRL_PIN(IMX8QM_MCLK_OUT0), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_GPIORHC), + IMX_PINCTRL_PIN(IMX8QM_SPI0_SCK), + IMX_PINCTRL_PIN(IMX8QM_SPI0_SDO), + IMX_PINCTRL_PIN(IMX8QM_SPI0_SDI), + IMX_PINCTRL_PIN(IMX8QM_SPI0_CS0), + IMX_PINCTRL_PIN(IMX8QM_SPI0_CS1), + IMX_PINCTRL_PIN(IMX8QM_SPI2_SCK), + IMX_PINCTRL_PIN(IMX8QM_SPI2_SDO), + IMX_PINCTRL_PIN(IMX8QM_SPI2_SDI), + IMX_PINCTRL_PIN(IMX8QM_SPI2_CS0), + IMX_PINCTRL_PIN(IMX8QM_SPI2_CS1), + IMX_PINCTRL_PIN(IMX8QM_SAI1_RXC), + IMX_PINCTRL_PIN(IMX8QM_SAI1_RXD), + IMX_PINCTRL_PIN(IMX8QM_SAI1_RXFS), + IMX_PINCTRL_PIN(IMX8QM_SAI1_TXC), + IMX_PINCTRL_PIN(IMX8QM_SAI1_TXD), + IMX_PINCTRL_PIN(IMX8QM_SAI1_TXFS), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_GPIORHT), + IMX_PINCTRL_PIN(IMX8QM_ADC_IN7), + IMX_PINCTRL_PIN(IMX8QM_ADC_IN6), + IMX_PINCTRL_PIN(IMX8QM_ADC_IN5), + IMX_PINCTRL_PIN(IMX8QM_ADC_IN4), + IMX_PINCTRL_PIN(IMX8QM_ADC_IN3), + IMX_PINCTRL_PIN(IMX8QM_ADC_IN2), + IMX_PINCTRL_PIN(IMX8QM_ADC_IN1), + IMX_PINCTRL_PIN(IMX8QM_ADC_IN0), + IMX_PINCTRL_PIN(IMX8QM_MLB_SIG), + IMX_PINCTRL_PIN(IMX8QM_MLB_CLK), + IMX_PINCTRL_PIN(IMX8QM_MLB_DATA), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_GPIOLHT), + IMX_PINCTRL_PIN(IMX8QM_FLEXCAN0_RX), + IMX_PINCTRL_PIN(IMX8QM_FLEXCAN0_TX), + IMX_PINCTRL_PIN(IMX8QM_FLEXCAN1_RX), + IMX_PINCTRL_PIN(IMX8QM_FLEXCAN1_TX), + IMX_PINCTRL_PIN(IMX8QM_FLEXCAN2_RX), + IMX_PINCTRL_PIN(IMX8QM_FLEXCAN2_TX), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_GPIOTHR), + IMX_PINCTRL_PIN(IMX8QM_USB_SS3_TC0), + IMX_PINCTRL_PIN(IMX8QM_USB_SS3_TC1), + IMX_PINCTRL_PIN(IMX8QM_USB_SS3_TC2), + IMX_PINCTRL_PIN(IMX8QM_USB_SS3_TC3), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_3V3_USB3IO), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_RESET_B), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_VSELECT), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_RESET_B), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_VSELECT), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_WP), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_CD_B), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_VSELSEP), + IMX_PINCTRL_PIN(IMX8QM_ENET0_MDIO), + IMX_PINCTRL_PIN(IMX8QM_ENET0_MDC), + IMX_PINCTRL_PIN(IMX8QM_ENET0_REFCLK_125M_25M), + IMX_PINCTRL_PIN(IMX8QM_ENET1_REFCLK_125M_25M), + IMX_PINCTRL_PIN(IMX8QM_ENET1_MDIO), + IMX_PINCTRL_PIN(IMX8QM_ENET1_MDC), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_GPIOCT), + IMX_PINCTRL_PIN(IMX8QM_QSPI1A_SS0_B), + IMX_PINCTRL_PIN(IMX8QM_QSPI1A_SS1_B), + IMX_PINCTRL_PIN(IMX8QM_QSPI1A_SCLK), + IMX_PINCTRL_PIN(IMX8QM_QSPI1A_DQS), + IMX_PINCTRL_PIN(IMX8QM_QSPI1A_DATA3), + IMX_PINCTRL_PIN(IMX8QM_QSPI1A_DATA2), + IMX_PINCTRL_PIN(IMX8QM_QSPI1A_DATA1), + IMX_PINCTRL_PIN(IMX8QM_QSPI1A_DATA0), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_QSPI1), + IMX_PINCTRL_PIN(IMX8QM_QSPI0A_DATA0), + IMX_PINCTRL_PIN(IMX8QM_QSPI0A_DATA1), + IMX_PINCTRL_PIN(IMX8QM_QSPI0A_DATA2), + IMX_PINCTRL_PIN(IMX8QM_QSPI0A_DATA3), + IMX_PINCTRL_PIN(IMX8QM_QSPI0A_DQS), + IMX_PINCTRL_PIN(IMX8QM_QSPI0A_SS0_B), + IMX_PINCTRL_PIN(IMX8QM_QSPI0A_SS1_B), + IMX_PINCTRL_PIN(IMX8QM_QSPI0A_SCLK), + IMX_PINCTRL_PIN(IMX8QM_QSPI0B_SCLK), + IMX_PINCTRL_PIN(IMX8QM_QSPI0B_DATA0), + IMX_PINCTRL_PIN(IMX8QM_QSPI0B_DATA1), + IMX_PINCTRL_PIN(IMX8QM_QSPI0B_DATA2), + IMX_PINCTRL_PIN(IMX8QM_QSPI0B_DATA3), + IMX_PINCTRL_PIN(IMX8QM_QSPI0B_DQS), + IMX_PINCTRL_PIN(IMX8QM_QSPI0B_SS0_B), + IMX_PINCTRL_PIN(IMX8QM_QSPI0B_SS1_B), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_QSPI0), + IMX_PINCTRL_PIN(IMX8QM_PCIE_CTRL0_CLKREQ_B), + IMX_PINCTRL_PIN(IMX8QM_PCIE_CTRL0_WAKE_B), + IMX_PINCTRL_PIN(IMX8QM_PCIE_CTRL0_PERST_B), + IMX_PINCTRL_PIN(IMX8QM_PCIE_CTRL1_CLKREQ_B), + IMX_PINCTRL_PIN(IMX8QM_PCIE_CTRL1_WAKE_B), + IMX_PINCTRL_PIN(IMX8QM_PCIE_CTRL1_PERST_B), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_PCIESEP), + IMX_PINCTRL_PIN(IMX8QM_USB_HSIC0_DATA), + IMX_PINCTRL_PIN(IMX8QM_USB_HSIC0_STROBE), + IMX_PINCTRL_PIN(IMX8QM_CALIBRATION_0_HSIC), + IMX_PINCTRL_PIN(IMX8QM_CALIBRATION_1_HSIC), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_CLK), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_CMD), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_DATA0), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_DATA1), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_DATA2), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_DATA3), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_DATA4), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_DATA5), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_DATA6), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_DATA7), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_STROBE), + IMX_PINCTRL_PIN(IMX8QM_EMMC0_RESET_B), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_SD1FIX), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_CLK), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_CMD), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_DATA0), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_DATA1), + IMX_PINCTRL_PIN(IMX8QM_CTL_NAND_RE_P_N), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_DATA2), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_DATA3), + IMX_PINCTRL_PIN(IMX8QM_CTL_NAND_DQS_P_N), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_DATA4), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_DATA5), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_DATA6), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_DATA7), + IMX_PINCTRL_PIN(IMX8QM_USDHC1_STROBE), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_VSEL2), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_CLK), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_CMD), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_DATA0), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_DATA1), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_DATA2), + IMX_PINCTRL_PIN(IMX8QM_USDHC2_DATA3), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_VSEL3), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_TXC), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_TX_CTL), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_TXD0), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_TXD1), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_TXD2), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_TXD3), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_RXC), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_RX_CTL), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_RXD0), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_RXD1), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_RXD2), + IMX_PINCTRL_PIN(IMX8QM_ENET0_RGMII_RXD3), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_TXC), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_TX_CTL), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_TXD0), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_TXD1), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_TXD2), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_TXD3), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_RXC), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_RX_CTL), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_RXD0), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_RXD1), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_RXD2), + IMX_PINCTRL_PIN(IMX8QM_ENET1_RGMII_RXD3), + IMX_PINCTRL_PIN(IMX8QM_COMP_CTL_GPIO_1V8_3V3_ENET_ENETA), +}; + +static const struct imx_pinctrl_soc_info imx8qm_pinctrl_info = { + .pins = imx8qm_pinctrl_pads, + .npins = ARRAY_SIZE(imx8qm_pinctrl_pads), + .flags = IMX_USE_SCU, +}; + +static const struct of_device_id imx8qm_pinctrl_of_match[] = { + { .compatible = "fsl,imx8qm-iomuxc", }, + { /* sentinel */ } +}; + +static int imx8qm_pinctrl_probe(struct platform_device *pdev) +{ + int ret; + + ret = imx_pinctrl_sc_ipc_init(pdev); + if (ret) + return ret; + + return imx_pinctrl_probe(pdev, &imx8qm_pinctrl_info); +} + +static struct platform_driver imx8qm_pinctrl_driver = { + .driver = { + .name = "imx8qm-pinctrl", + .of_match_table = of_match_ptr(imx8qm_pinctrl_of_match), + .suppress_bind_attrs = true, + }, + .probe = imx8qm_pinctrl_probe, +}; + +static int __init imx8qm_pinctrl_init(void) +{ + return platform_driver_register(&imx8qm_pinctrl_driver); +} +arch_initcall(imx8qm_pinctrl_init); -- cgit v1.2.3 From 823868fceae3bac07cf5eccb128d6916e7a5ae9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 21 Dec 2018 18:32:57 +0100 Subject: pinctrl: armada-37xx: Correct mpp definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a cleanup and fix of the patch by Ken Ma . Fix the mpp definitions according to newest revision of the specification: - northbridge: fix pmic1 gpio number to 7 fix pmic0 gpio number to 6 - southbridge split pcie1 group bit mask to BIT(5) and BIT(9) fix ptp group bit mask to BIT(11) | BIT(12) | BIT(13) add smi group with bit mask BIT(4) [gregory: split the pcie group in 2, as at hardware level they can be configured separately] Signed-off-by: Marek Behún Signed-off-by: Gregory CLEMENT Tested-by: Miquel Raynal Signed-off-by: Linus Walleij --- drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index aa48b3f23c7f..267dfc530985 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -170,8 +170,8 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = { PIN_GRP_GPIO("pwm1", 12, 1, BIT(4), "pwm"), PIN_GRP_GPIO("pwm2", 13, 1, BIT(5), "pwm"), PIN_GRP_GPIO("pwm3", 14, 1, BIT(6), "pwm"), - PIN_GRP_GPIO("pmic1", 17, 1, BIT(7), "pmic"), - PIN_GRP_GPIO("pmic0", 16, 1, BIT(8), "pmic"), + PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"), + PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"), PIN_GRP_GPIO("i2c2", 2, 2, BIT(9), "i2c"), PIN_GRP_GPIO("i2c1", 0, 2, BIT(10), "i2c"), PIN_GRP_GPIO("spi_cs1", 17, 1, BIT(12), "spi"), @@ -195,8 +195,10 @@ static struct armada_37xx_pin_group armada_37xx_sb_groups[] = { PIN_GRP_GPIO("usb2_drvvbus1", 1, 1, BIT(1), "drvbus"), PIN_GRP_GPIO("sdio_sb", 24, 6, BIT(2), "sdio"), PIN_GRP_GPIO("rgmii", 6, 12, BIT(3), "mii"), - PIN_GRP_GPIO("pcie1", 3, 2, BIT(4), "pcie"), - PIN_GRP_GPIO("ptp", 20, 3, BIT(5), "ptp"), + PIN_GRP_GPIO("smi", 18, 2, BIT(4), "smi"), + PIN_GRP_GPIO("pcie1", 3, 1, BIT(5), "pcie"), + PIN_GRP_GPIO("pcie1_clkreq", 4, 1, BIT(9), "pcie"), + PIN_GRP_GPIO("ptp", 20, 3, BIT(11) | BIT(12) | BIT(13), "ptp"), PIN_GRP("ptp_clk", 21, 1, BIT(6), "ptp", "mii"), PIN_GRP("ptp_trig", 22, 1, BIT(7), "ptp", "mii"), PIN_GRP_GPIO_3("mii_col", 23, 1, BIT(8) | BIT(14), 0, BIT(8), BIT(14), -- cgit v1.2.3 From 4d98fbaacd79a82f408febb66a9c42fe42361b16 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 21 Dec 2018 18:32:58 +0100 Subject: pinctrl: armada-37xx: add missing pin: PCIe1 Wakeup Declare the PCIe1 Wakeup which was initially missing. Signed-off-by: Gregory CLEMENT Tested-by: Miquel Raynal Signed-off-by: Linus Walleij --- drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 267dfc530985..4b9f2cf94431 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -198,6 +198,7 @@ static struct armada_37xx_pin_group armada_37xx_sb_groups[] = { PIN_GRP_GPIO("smi", 18, 2, BIT(4), "smi"), PIN_GRP_GPIO("pcie1", 3, 1, BIT(5), "pcie"), PIN_GRP_GPIO("pcie1_clkreq", 4, 1, BIT(9), "pcie"), + PIN_GRP_GPIO("pcie1_wakeup", 5, 1, BIT(10), "pcie"), PIN_GRP_GPIO("ptp", 20, 3, BIT(11) | BIT(12) | BIT(13), "ptp"), PIN_GRP("ptp_clk", 21, 1, BIT(6), "ptp", "mii"), PIN_GRP("ptp_trig", 22, 1, BIT(7), "ptp", "mii"), -- cgit v1.2.3 From e4889362e0389e95970d28707599aa8e08c35b51 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 31 Dec 2018 17:52:56 +0800 Subject: gpio: sama5d2-piobu: Set proper output level for direction_output Set proper output level base on the argument of direction_output. Also remove sama5d2_piobu_set_direction() as there is only one caller now. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sama5d2-piobu.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-sama5d2-piobu.c b/drivers/gpio/gpio-sama5d2-piobu.c index 03a000659fa1..7d718557092e 100644 --- a/drivers/gpio/gpio-sama5d2-piobu.c +++ b/drivers/gpio/gpio-sama5d2-piobu.c @@ -108,16 +108,6 @@ static int sama5d2_piobu_read_value(struct gpio_chip *chip, unsigned int pin, return val & mask; } -/** - * sama5d2_piobu_set_direction() - mark pin as input or output - */ -static int sama5d2_piobu_set_direction(struct gpio_chip *chip, - unsigned int direction, - unsigned int pin) -{ - return sama5d2_piobu_write_value(chip, pin, PIOBU_DIRECTION, direction); -} - /** * sama5d2_piobu_get_direction() - gpiochip get_direction */ @@ -138,7 +128,7 @@ static int sama5d2_piobu_get_direction(struct gpio_chip *chip, static int sama5d2_piobu_direction_input(struct gpio_chip *chip, unsigned int pin) { - return sama5d2_piobu_set_direction(chip, PIOBU_IN, pin); + return sama5d2_piobu_write_value(chip, pin, PIOBU_DIRECTION, PIOBU_IN); } /** @@ -147,7 +137,13 @@ static int sama5d2_piobu_direction_input(struct gpio_chip *chip, static int sama5d2_piobu_direction_output(struct gpio_chip *chip, unsigned int pin, int value) { - return sama5d2_piobu_set_direction(chip, PIOBU_OUT, pin); + unsigned int val = PIOBU_OUT; + + if (value) + val |= PIOBU_HIGH; + + return sama5d2_piobu_write_value(chip, pin, PIOBU_DIRECTION | PIOBU_SOD, + val); } /** -- cgit v1.2.3 From 0a64d62d5399ee7881884704fe9848a791c4bac6 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Tue, 8 Jan 2019 11:31:47 +0000 Subject: staging: erofs: fixed -Wmissing-prototype warnings by making functions static. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define three functions which are not used outside their own translation-units as static in order to fix the following warnings: drivers/staging/erofs/utils.c:134:6: warning: no previous prototype for ‘erofs_try_to_release_workgroup’ [-Wmissing-prototypes] bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/staging/erofs/unzip_vle.c:592:6: warning: no previous prototype for ‘z_erofs_vle_work_release’ [-Wmissing-prototypes] void z_erofs_vle_work_release(struct z_erofs_vle_work *work) ^~~~~~~~~~~~~~~~~~~~~~~~ drivers/staging/erofs/unzip_vle_lz4.c:16:5: warning: no previous prototype for ‘z_erofs_unzip_lz4’ [-Wmissing-prototypes] int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen) ^~~~~~~~~~~~~~~~~ Signed-off-by: Jeremy Sowden Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/unzip_vle.c | 2 +- drivers/staging/erofs/unzip_vle_lz4.c | 2 +- drivers/staging/erofs/utils.c | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/unzip_vle.c b/drivers/staging/erofs/unzip_vle.c index 4ac1099a39c6..584612b47369 100644 --- a/drivers/staging/erofs/unzip_vle.c +++ b/drivers/staging/erofs/unzip_vle.c @@ -589,7 +589,7 @@ static void __z_erofs_vle_work_release(struct z_erofs_vle_workgroup *grp, erofs_workgroup_put(&grp->obj); } -void z_erofs_vle_work_release(struct z_erofs_vle_work *work) +static void z_erofs_vle_work_release(struct z_erofs_vle_work *work) { struct z_erofs_vle_workgroup *grp = z_erofs_vle_work_workgroup(work, true); diff --git a/drivers/staging/erofs/unzip_vle_lz4.c b/drivers/staging/erofs/unzip_vle_lz4.c index 52797bd89da1..8e8d705a6861 100644 --- a/drivers/staging/erofs/unzip_vle_lz4.c +++ b/drivers/staging/erofs/unzip_vle_lz4.c @@ -13,7 +13,7 @@ #include "unzip_vle.h" #include -int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen) +static int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen) { int ret = LZ4_decompress_safe_partial(in, out, inlen, outlen, outlen); diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c index b535898ca753..fc30025ef101 100644 --- a/drivers/staging/erofs/utils.c +++ b/drivers/staging/erofs/utils.c @@ -131,9 +131,9 @@ static void erofs_workgroup_unfreeze_final(struct erofs_workgroup *grp) __erofs_workgroup_free(grp); } -bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi, - struct erofs_workgroup *grp, - bool cleanup) +static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi, + struct erofs_workgroup *grp, + bool cleanup) { /* * for managed cache enabled, the refcount of workgroups @@ -172,9 +172,9 @@ bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi, #else /* for nocache case, no customized reclaim path at all */ -bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi, - struct erofs_workgroup *grp, - bool cleanup) +static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi, + struct erofs_workgroup *grp, + bool cleanup) { int cnt = atomic_read(&grp->refcount); -- cgit v1.2.3 From e7dfb1cff65b1ac6f1175f3080f6b74272f338f1 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Tue, 8 Jan 2019 11:31:48 +0000 Subject: staging: erofs: fixed -Wmissing-prototype warnings by moving prototypes to header file. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved prototypes for two functions to a header file in order to fix the following warnings: drivers/staging/erofs/unzip_vle.c:577:6: warning: no previous prototype for ‘erofs_workgroup_free_rcu’ [-Wmissing-prototypes] void erofs_workgroup_free_rcu(struct erofs_workgroup *grp) ^~~~~~~~~~~~~~~~~~~~~~~~ drivers/staging/erofs/unzip_vle.c:1702:5: warning: no previous prototype for ‘z_erofs_map_blocks_iter’ [-Wmissing-prototypes] int z_erofs_map_blocks_iter(struct inode *inode, ^~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Jeremy Sowden Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/data.c | 6 ------ drivers/staging/erofs/internal.h | 7 +++++++ drivers/staging/erofs/utils.c | 2 -- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/data.c b/drivers/staging/erofs/data.c index 5a55f0bfdfbb..329fa4fa3e9c 100644 --- a/drivers/staging/erofs/data.c +++ b/drivers/staging/erofs/data.c @@ -165,12 +165,6 @@ err_out: return err; } -#ifdef CONFIG_EROFS_FS_ZIP -extern int z_erofs_map_blocks_iter(struct inode *, - struct erofs_map_blocks *, - struct page **, int); -#endif - int erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map, struct page **mpage_ret, int flags) diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index 49c587383315..192f4028d85d 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -288,6 +288,8 @@ static inline void erofs_workstation_cleanup_all(struct super_block *sb) erofs_shrink_workstation(EROFS_SB(sb), ~0UL, true); } +extern void erofs_workgroup_free_rcu(struct erofs_workgroup *grp); + #ifdef EROFS_FS_HAS_MANAGED_CACHE extern int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, struct erofs_workgroup *egrp); @@ -530,6 +532,11 @@ struct erofs_map_blocks_iter { struct page *mpage; }; +#ifdef CONFIG_EROFS_FS_ZIP +extern int z_erofs_map_blocks_iter(struct inode *, + struct erofs_map_blocks *, + struct page **, int); +#endif static inline struct page * erofs_get_inline_page(struct inode *inode, diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c index fc30025ef101..aed211cd5875 100644 --- a/drivers/staging/erofs/utils.c +++ b/drivers/staging/erofs/utils.c @@ -104,8 +104,6 @@ int erofs_register_workgroup(struct super_block *sb, return err; } -extern void erofs_workgroup_free_rcu(struct erofs_workgroup *grp); - static void __erofs_workgroup_free(struct erofs_workgroup *grp) { atomic_long_dec(&erofs_global_shrink_cnt); -- cgit v1.2.3 From 4b03f3f4ccb83c0d76ff61343a4267eac30f9e0c Mon Sep 17 00:00:00 2001 From: Sidong Yang Date: Tue, 8 Jan 2019 13:24:54 +0000 Subject: staging: erofs: Add identifier for function definition arguments Add identifier for function definition arguments in xattr_iter_handlers, this change clears the checkpatch.pl issue and make code more explicit. Signed-off-by: Sidong Yang Reviewed-by: Gao Xiang Reviewed-by: Chao Yu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/xattr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/xattr.c b/drivers/staging/erofs/xattr.c index 80dca6a4adbe..59bc5641c4e7 100644 --- a/drivers/staging/erofs/xattr.c +++ b/drivers/staging/erofs/xattr.c @@ -117,10 +117,12 @@ static int init_inode_xattrs(struct inode *inode) * and need to be handled */ struct xattr_iter_handlers { - int (*entry)(struct xattr_iter *, struct erofs_xattr_entry *); - int (*name)(struct xattr_iter *, unsigned int, char *, unsigned int); - int (*alloc_buffer)(struct xattr_iter *, unsigned int); - void (*value)(struct xattr_iter *, unsigned int, char *, unsigned int); + int (*entry)(struct xattr_iter *_it, struct erofs_xattr_entry *entry); + int (*name)(struct xattr_iter *_it, unsigned int processed, char *buf, + unsigned int len); + int (*alloc_buffer)(struct xattr_iter *_it, unsigned int value_sz); + void (*value)(struct xattr_iter *_it, unsigned int processed, char *buf, + unsigned int len); }; static inline int xattr_iter_fixup(struct xattr_iter *it) -- cgit v1.2.3 From ba93c357229fd4666fe60f8d7ec97659882727c0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 30 Dec 2018 16:53:15 +0100 Subject: iommu/msm: Reduce indentation Delete tab aligning a statement with the right hand side of a preceding assignment rather than the left hand side. Found with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Joerg Roedel --- drivers/iommu/msm_iommu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index fc4270733f11..6dde3a9db92e 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -461,10 +461,10 @@ static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) master->num = msm_iommu_alloc_ctx(iommu->context_map, 0, iommu->ncb); - if (IS_ERR_VALUE(master->num)) { - ret = -ENODEV; - goto fail; - } + if (IS_ERR_VALUE(master->num)) { + ret = -ENODEV; + goto fail; + } config_mids(iommu, master); __program_context(iommu->base, master->num, priv); -- cgit v1.2.3 From bd3c2e66e4cb91ed9294b5da920deeb45db0c13a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 2 Jan 2019 23:16:57 +0200 Subject: iommu/iova: Allow compiling the library without IOMMU support Drivers such as the Intel IPU3 ImgU driver use the IOVA library to manage the device's own virtual address space while not implementing the IOMMU API. Currently the IOVA library is only compiled if the IOMMU support is enabled, resulting into a failure during linking due to missing symbols. Fix this by defining IOVA library Kconfig bits independently of IOMMU support configuration, and descending to the iommu directory unconditionally during the build. Signed-off-by: Sakari Ailus Signed-off-by: Joerg Roedel --- drivers/Makefile | 2 +- drivers/iommu/Kconfig | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/Makefile b/drivers/Makefile index e1ce029d28fd..04da7876032c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -56,7 +56,7 @@ obj-y += tty/ obj-y += char/ # iommu/ comes before gpu as gpu are using iommu controllers -obj-$(CONFIG_IOMMU_SUPPORT) += iommu/ +obj-y += iommu/ # gpu/ comes after char for AGP vs DRM startup and after iommu obj-y += gpu/ diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index d9a25715650e..d2c83e62873d 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -1,3 +1,7 @@ +# The IOVA library may also be used by non-IOMMU_API users +config IOMMU_IOVA + tristate + # IOMMU_API always gets selected by whoever wants it. config IOMMU_API bool @@ -81,9 +85,6 @@ config IOMMU_DEFAULT_PASSTHROUGH If unsure, say N here. -config IOMMU_IOVA - tristate - config OF_IOMMU def_bool y depends on OF && IOMMU_API -- cgit v1.2.3 From 5b438f4ba315db4f8c1489d175656798d58c014f Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Fri, 11 Jan 2019 13:04:57 +0800 Subject: iommu/vt-d: Support page request in scalable mode VT-d Rev3.0 has made a few changes to the page request interface, 1. widened PRQ descriptor from 128 bits to 256 bits; 2. removed streaming response type; 3. introduced private data that requires page response even the request is not last request in group (LPIG). This is a supplement to commit 1c4f88b7f1f92 ("iommu/vt-d: Shared virtual address in scalable mode") and makes the svm code compliant with VT-d Rev3.0. Cc: Ashok Raj Cc: Liu Yi L Cc: Kevin Tian Signed-off-by: Jacob Pan Fixes: 1c4f88b7f1f92 ("iommu/vt-d: Shared virtual address in scalable mode") Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/intel-svm.c | 77 +++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index a2a2aa4439aa..79add5716552 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -470,20 +470,31 @@ EXPORT_SYMBOL_GPL(intel_svm_is_pasid_valid); /* Page request queue descriptor */ struct page_req_dsc { - u64 srr:1; - u64 bof:1; - u64 pasid_present:1; - u64 lpig:1; - u64 pasid:20; - u64 bus:8; - u64 private:23; - u64 prg_index:9; - u64 rd_req:1; - u64 wr_req:1; - u64 exe_req:1; - u64 priv_req:1; - u64 devfn:8; - u64 addr:52; + union { + struct { + u64 type:8; + u64 pasid_present:1; + u64 priv_data_present:1; + u64 rsvd:6; + u64 rid:16; + u64 pasid:20; + u64 exe_req:1; + u64 pm_req:1; + u64 rsvd2:10; + }; + u64 qw_0; + }; + union { + struct { + u64 rd_req:1; + u64 wr_req:1; + u64 lpig:1; + u64 prg_index:9; + u64 addr:52; + }; + u64 qw_1; + }; + u64 priv_data[2]; }; #define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x10) @@ -596,7 +607,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) /* Accounting for major/minor faults? */ rcu_read_lock(); list_for_each_entry_rcu(sdev, &svm->devs, list) { - if (sdev->sid == PCI_DEVID(req->bus, req->devfn)) + if (sdev->sid == req->rid) break; } /* Other devices can go away, but the drivers are not permitted @@ -609,33 +620,35 @@ static irqreturn_t prq_event_thread(int irq, void *d) if (sdev && sdev->ops && sdev->ops->fault_cb) { int rwxp = (req->rd_req << 3) | (req->wr_req << 2) | - (req->exe_req << 1) | (req->priv_req); - sdev->ops->fault_cb(sdev->dev, req->pasid, req->addr, req->private, rwxp, result); + (req->exe_req << 1) | (req->pm_req); + sdev->ops->fault_cb(sdev->dev, req->pasid, req->addr, + req->priv_data, rwxp, result); } /* We get here in the error case where the PASID lookup failed, and these can be NULL. Do not use them below this point! */ sdev = NULL; svm = NULL; no_pasid: - if (req->lpig) { - /* Page Group Response */ + if (req->lpig || req->priv_data_present) { + /* + * Per VT-d spec. v3.0 ch7.7, system software must + * respond with page group response if private data + * is present (PDP) or last page in group (LPIG) bit + * is set. This is an additional VT-d feature beyond + * PCI ATS spec. + */ resp.qw0 = QI_PGRP_PASID(req->pasid) | - QI_PGRP_DID((req->bus << 8) | req->devfn) | + QI_PGRP_DID(req->rid) | QI_PGRP_PASID_P(req->pasid_present) | + QI_PGRP_PDP(req->pasid_present) | + QI_PGRP_RESP_CODE(result) | QI_PGRP_RESP_TYPE; resp.qw1 = QI_PGRP_IDX(req->prg_index) | - QI_PGRP_PRIV(req->private) | - QI_PGRP_RESP_CODE(result); - } else if (req->srr) { - /* Page Stream Response */ - resp.qw0 = QI_PSTRM_IDX(req->prg_index) | - QI_PSTRM_PRIV(req->private) | - QI_PSTRM_BUS(req->bus) | - QI_PSTRM_PASID(req->pasid) | - QI_PSTRM_RESP_TYPE; - resp.qw1 = QI_PSTRM_ADDR(address) | - QI_PSTRM_DEVFN(req->devfn) | - QI_PSTRM_RESP_CODE(result); + QI_PGRP_LPIG(req->lpig); + + if (req->priv_data_present) + memcpy(&resp.qw2, req->priv_data, + sizeof(req->priv_data)); } resp.qw2 = 0; resp.qw3 = 0; -- cgit v1.2.3 From 6e737a4e921ea99125955d0d8821d8da129b03bd Mon Sep 17 00:00:00 2001 From: "chuanjia.liu" Date: Thu, 3 Jan 2019 11:37:15 +0800 Subject: pinctrl: mediatek: add EINT support to virtual GPIOs Virtual gpio only used inside SOC and not being exported to outside SOC. Some modules use virtual gpio as eint and doesn't need SMT. So this patch add EINT support to virtual GPIOs. Signed-off-by: Chuanjia Liu Acked-by: Sean Wang Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c index 4a9e0d4c2bbc..b1c368455d30 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c @@ -290,7 +290,13 @@ static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n) return err; err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, MTK_ENABLE); - if (err) + /* SMT is supposed to be supported by every real GPIO and doesn't + * support virtual GPIOs, so the extra condition err != -ENOTSUPP + * is just for adding EINT support to these virtual GPIOs. It should + * add an extra flag in the pin descriptor when more pins with + * distinctive characteristic come out. + */ + if (err && err != -ENOTSUPP) return err; return 0; -- cgit v1.2.3 From 16f4372fd7a5a560abe0edb4c68be1200599dc8a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 11:37:33 -0600 Subject: pinctrl: mcp23s08: use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-mcp23s08.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index b03481ef99a1..6b4def13df8f 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -1139,8 +1139,7 @@ static int mcp23s08_probe(struct spi_device *spi) return -ENODEV; data = devm_kzalloc(&spi->dev, - sizeof(*data) + chips * sizeof(struct mcp23s08), - GFP_KERNEL); + struct_size(data, chip, chips), GFP_KERNEL); if (!data) return -ENOMEM; -- cgit v1.2.3 From 1e11820f72b71d276ae8fdc64fee7cdb49c05bc6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 15:35:08 -0600 Subject: pinctrl: sirf: atlas7: use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Linus Walleij --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index 4ba171827428..8a0eee044264 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -6007,8 +6007,8 @@ static int atlas7_gpio_probe(struct platform_device *pdev) } /* retrieve gpio descriptor data */ - a7gc = devm_kzalloc(&pdev->dev, sizeof(*a7gc) + - sizeof(struct atlas7_gpio_bank) * nbank, GFP_KERNEL); + a7gc = devm_kzalloc(&pdev->dev, struct_size(a7gc, banks, nbank), + GFP_KERNEL); if (!a7gc) return -ENOMEM; -- cgit v1.2.3 From 48c67f1fc663d86bbd486a2c664ba130e7c70790 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Fri, 4 Jan 2019 22:49:12 +0100 Subject: pinctrl/amd: fix typo Fix spelling mistake: "lenght" -> "length" Signed-off-by: Matteo Croce Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-amd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 2a7d638978d8..6689995fa3aa 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -489,7 +489,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) /* * If WAKE_INT_MASTER_REG.MaskStsEn is set, a software write to the * debounce registers of any GPIO will block wake/interrupt status - * generation for *all* GPIOs for a lenght of time that depends on + * generation for *all* GPIOs for a length of time that depends on * WAKE_INT_MASTER_REG.MaskStsLength[11:0]. During this period the * INTERRUPT_ENABLE bit will read as 0. * -- cgit v1.2.3 From 9fe310546559d123103c39dc85eb54dc1316f450 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Nov 2018 12:29:44 +0100 Subject: mt76: add size check for additional rx fragments So far the code only validates the buffer size of the first skb. Extend this check to cover additional fragments as well, in case the size is corrupted during a DMA reset. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index e2ba26378575..710a77fccf63 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -430,6 +430,14 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) if (!data) break; + if (q->buf_size < len + q->buf_offset) { + dev_kfree_skb(q->rx_head); + q->rx_head = NULL; + + skb_free_frag(data); + continue; + } + if (q->rx_head) { mt76_add_fragment(dev, q, data, len, more); continue; -- cgit v1.2.3 From cbbfd73767cd7a43fbebe712cb837d7ff06b99f2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 29 Nov 2018 13:13:54 +0100 Subject: mt76: throttle transmission of buffered multicast packets Avoids drowning out regular transmissions Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 66315410aebe..6974acc75e2b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -121,9 +121,10 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg) ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, mt76x02_add_buffered_bc, &data); - } while (nframes != skb_queue_len(&data.q)); + } while (nframes != skb_queue_len(&data.q) && + skb_queue_len(&data.q) < 8); - if (!nframes) + if (!skb_queue_len(&data.q)) return; for (i = 0; i < ARRAY_SIZE(data.tail); i++) { -- cgit v1.2.3 From 7267a7965dd7b0f2a0800538c8080f3e683846fc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 13 Nov 2018 20:54:17 +0100 Subject: mt76: request tx status for powersave released EOSP packet Allows mac80211 to keep track of the service period Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 7b711058807d..f08509c1670d 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -330,7 +330,8 @@ mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta, info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; if (last) - info->flags |= IEEE80211_TX_STATUS_EOSP; + info->flags |= IEEE80211_TX_STATUS_EOSP | + IEEE80211_TX_CTL_REQ_TX_STATUS; mt76_skb_set_moredata(skb, !last); dev->queue_ops->tx_queue_skb(dev, hwq, skb, wcid, sta); -- cgit v1.2.3 From 4d4b12bc56d33d68ad04382f4c15c42bf4616270 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 1 Dec 2018 10:55:06 +0100 Subject: mt76: dma: remove napi from mt76_dma_rx_fill signature Remove napi from mt76_dma_rx_fill routine signature since it is a leftover of a previous implementation and it is no longer used Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 710a77fccf63..b7fd2e110663 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -318,7 +318,7 @@ free: EXPORT_SYMBOL_GPL(mt76_dma_tx_queue_skb); static int -mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi) +mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) { dma_addr_t addr; void *buf; @@ -392,7 +392,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) mt76_dma_rx_cleanup(dev, q); mt76_dma_sync_idx(dev, q); - mt76_dma_rx_fill(dev, q, false); + mt76_dma_rx_fill(dev, q); } static void @@ -471,7 +471,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) dev->drv->rx_skb(dev, q - dev->q_rx, skb); } - mt76_dma_rx_fill(dev, q, true); + mt76_dma_rx_fill(dev, q); return done; } @@ -512,7 +512,7 @@ mt76_dma_init(struct mt76_dev *dev) for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) { netif_napi_add(&dev->napi_dev, &dev->napi[i], mt76_dma_rx_poll, 64); - mt76_dma_rx_fill(dev, &dev->q_rx[i], false); + mt76_dma_rx_fill(dev, &dev->q_rx[i]); skb_queue_head_init(&dev->rx_skb[i]); napi_enable(&dev->napi[i]); } -- cgit v1.2.3 From 0ecf94dc3695a494dd4f495fc0913049d0e99891 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 1 Dec 2018 15:01:19 +0100 Subject: mt76: usb: do not build the skb if reported len does not fit in buf_size Precompute data length in order to avoid to allocate the related skb data structure if reported length does not fit in queue buf_size Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index b061263453d4..14ff06c5764e 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -407,17 +407,15 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb) if (len < 0) return 0; + data_len = min_t(int, len, urb->sg[0].length - MT_DMA_HDR_LEN); + if (MT_DMA_HDR_LEN + data_len > SKB_WITH_OVERHEAD(q->buf_size)) + return 0; + skb = build_skb(data, q->buf_size); if (!skb) return 0; - data_len = min_t(int, len, urb->sg[0].length - MT_DMA_HDR_LEN); skb_reserve(skb, MT_DMA_HDR_LEN); - if (skb->tail + data_len > skb->end) { - dev_kfree_skb(skb); - return 1; - } - __skb_put(skb, data_len); len -= data_len; -- cgit v1.2.3 From 85b7e2acd31bf975c5163e0c6d949fa3742921b1 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 2 Dec 2018 13:06:34 +0100 Subject: mt76: Add missing include of linux/module.h MODULE_FIRMWARE() is used in usb_mcu.c and provided by linux/module.h, but this header file is not directly included. This causes problems in backports with some kernel versions. Add the missing include. Signed-off-by: Hauke Mehrtens Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c index 9d7585029df9..f391d2d21fbc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c @@ -15,6 +15,7 @@ */ #include #include +#include #include "mt76x0.h" #include "mcu.h" -- cgit v1.2.3 From 374eb1b55540c99af4e2417a2d51ff5f56cfdb70 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Dec 2018 12:40:23 +0100 Subject: mt76: fix typo in mt76x02_check_mac_err routine Reconfigure properly MT_MAC_SYS_CTRL register after mac sw-reset in mt76x02_check_mac_err routine Fixes: 73556561ab9f ("mt76x0: use mt76x02_mac_work as stats handler") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index c08bf371e527..490368dc9325 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -774,8 +774,8 @@ static void mt76x02_check_mac_err(struct mt76x02_dev *dev) mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); udelay(10); - mt76_clear(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); } void mt76x02_mac_work(struct work_struct *work) -- cgit v1.2.3 From 4989338ed3053372fcf5173a2a4800ac99de07d9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Dec 2018 17:07:39 +0100 Subject: mt76: mac: run mt76x02_mac_work routine atomically Grab mt76_dev mutex in mt76x02_mac_work handler since it runs concurrently with mt76x{0,2}_set_channel routines Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 490368dc9325..64841f40cdcf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -784,6 +784,8 @@ void mt76x02_mac_work(struct work_struct *work) mac_work.work); int i, idx; + mutex_lock(&dev->mt76.mutex); + mt76x02_update_channel(&dev->mt76); for (i = 0, idx = 0; i < 16; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); @@ -796,6 +798,8 @@ void mt76x02_mac_work(struct work_struct *work) if (!dev->beacon_mask) mt76x02_check_mac_err(dev); + mutex_unlock(&dev->mt76.mutex); + mt76_tx_status_check(&dev->mt76, NULL, false); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, -- cgit v1.2.3 From e207afa0232d40606e025059c18c70b89a7d5912 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Dec 2018 19:11:55 +0100 Subject: mt76: usb: avoid queue/status spinlocks while passing tx status to mac80211 As already done for pcie code in commit 79d1c94c9c78 ("mt76: avoid queue/status spinlocks while passing tx status to mac80211") make sure that no tx related spinlocks are taken during the ieee80211_tx_status call Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 14ff06c5764e..6a2507524c6c 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -583,6 +583,7 @@ static void mt76u_stop_rx(struct mt76_dev *dev) static void mt76u_tx_tasklet(unsigned long data) { struct mt76_dev *dev = (struct mt76_dev *)data; + struct mt76_queue_entry entry; struct mt76u_buf *buf; struct mt76_queue *q; bool wake; @@ -597,17 +598,18 @@ static void mt76u_tx_tasklet(unsigned long data) if (!buf->done || !q->queued) break; - dev->drv->tx_complete_skb(dev, q, - &q->entry[q->head], - false); - if (q->entry[q->head].schedule) { q->entry[q->head].schedule = false; q->swq_queued--; } + entry = q->entry[q->head]; q->head = (q->head + 1) % q->ndesc; q->queued--; + + spin_unlock_bh(&q->lock); + dev->drv->tx_complete_skb(dev, q, &entry, false); + spin_lock_bh(&q->lock); } mt76_txq_schedule(dev, q); wake = i < IEEE80211_NUM_ACS && q->queued < q->ndesc - 8; -- cgit v1.2.3 From b9f81643b6aea47602adc3a61edf5ad207d640ec Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 10 Dec 2018 11:22:00 +0100 Subject: mt76x0: pci: fix ACS support Fix Automatic Channel Selection (ACS) support in mt76x0e driver configuring properly MT_CH_TIME_CFG register Fixes: 6250318694ca ("mt76x0: pci: add get_survey support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index d895b6f3dc44..1906cc62690f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -141,6 +141,14 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) mt76_clear(dev, 0x110, BIT(9)); mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); + mt76_wr(dev, MT_CH_TIME_CFG, + MT_CH_TIME_CFG_TIMER_EN | + MT_CH_TIME_CFG_TX_AS_BUSY | + MT_CH_TIME_CFG_RX_AS_BUSY | + MT_CH_TIME_CFG_NAV_AS_BUSY | + MT_CH_TIME_CFG_EIFS_AS_BUSY | + FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); + err = mt76x0_register_device(dev); if (err < 0) return err; -- cgit v1.2.3 From 20ce270e5a7da08fdf946ed674ba10c71d18fdfb Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 10 Dec 2018 11:53:55 +0100 Subject: mt76x02: do not set protection on set_rts_threshold callback Use set_rts_threshold calback to enable/disable threshold only for legacy traffic. Protection for HT and VHT traffic is defined by HT operation element and it's provided by remote AP or by hostapd. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 16 +--------------- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 +- 3 files changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 64841f40cdcf..d3f1d57fb758 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -715,7 +715,7 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, } EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); -void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val) +void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val) { u32 data = 0; @@ -729,20 +729,6 @@ void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val) MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); mt76_rmw(dev, MT_OFDM_PROT_CFG, MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_MM20_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_MM40_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_GF20_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_GF40_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_TX_PROT_CFG6, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_TX_PROT_CFG7, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_TX_PROT_CFG8, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); } void mt76x02_update_channel(struct mt76_dev *mdev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 4e597004c445..d1a8ed171537 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -194,7 +194,7 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, struct mt76x02_tx_status *stat, u8 *update); int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, void *rxi); -void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val); +void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val); void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr); void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 38bd466cff16..364e7b2ebf99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -463,7 +463,7 @@ int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) return -EINVAL; mutex_lock(&dev->mt76.mutex); - mt76x02_mac_set_tx_protection(dev, val); + mt76x02_mac_set_rts_thresh(dev, val); mutex_unlock(&dev->mt76.mutex); return 0; -- cgit v1.2.3 From 493d2dfab34bb88563a6a64801c7d604537ca958 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 10 Dec 2018 11:53:56 +0100 Subject: mt76x02: fixup MT_PROT_RATE_* defines On new mt76 chips, phy mode is configured by last 3 bits of rate value. Hence OFDM bit is marked by 0x2000 instead of 0x4000. Acked-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_regs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index f7de77d09d28..d1ac847adce5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -440,9 +440,9 @@ #define MT_PROT_TXOP_ALLOW_GF40 BIT(25) #define MT_PROT_RTS_THR_EN BIT(26) #define MT_PROT_RATE_CCK_11 0x0003 -#define MT_PROT_RATE_OFDM_6 0x4000 -#define MT_PROT_RATE_OFDM_24 0x4004 -#define MT_PROT_RATE_DUP_OFDM_24 0x4084 +#define MT_PROT_RATE_OFDM_6 0x2000 +#define MT_PROT_RATE_OFDM_24 0x2004 +#define MT_PROT_RATE_DUP_OFDM_24 0x2084 #define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20) #define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \ ~MT_PROT_TXOP_ALLOW_MM40 & \ -- cgit v1.2.3 From 26a7b5473191d362b09a190fafd0dc2059cbf527 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 10 Dec 2018 11:53:57 +0100 Subject: mt76x02: set protection according to ht operation element Configure protection based on information that are provided to us either by remote AP or by hostapd via HT operation IE. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 83 +++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 2 + drivers/net/wireless/mediatek/mt76/mt76x02_regs.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 4 ++ 4 files changed, 90 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index d3f1d57fb758..ddc1c3146feb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -731,6 +731,89 @@ void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val) MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); } +void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot, + int ht_mode) +{ + int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; + bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + u32 prot[6]; + u32 vht_prot[3]; + int i; + u16 rts_thr; + + for (i = 0; i < ARRAY_SIZE(prot); i++) { + prot[i] = mt76_rr(dev, MT_CCK_PROT_CFG + i * 4); + prot[i] &= ~MT_PROT_CFG_CTRL; + if (i >= 2) + prot[i] &= ~MT_PROT_CFG_RATE; + } + + for (i = 0; i < ARRAY_SIZE(vht_prot); i++) { + vht_prot[i] = mt76_rr(dev, MT_TX_PROT_CFG6 + i * 4); + vht_prot[i] &= ~(MT_PROT_CFG_CTRL | MT_PROT_CFG_RATE); + } + + rts_thr = mt76_get_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH); + + if (rts_thr != 0xffff) + prot[0] |= MT_PROT_CTRL_RTS_CTS; + + if (legacy_prot) { + prot[1] |= MT_PROT_CTRL_CTS2SELF; + + prot[2] |= MT_PROT_RATE_CCK_11; + prot[3] |= MT_PROT_RATE_CCK_11; + prot[4] |= MT_PROT_RATE_CCK_11; + prot[5] |= MT_PROT_RATE_CCK_11; + + vht_prot[0] |= MT_PROT_RATE_CCK_11; + vht_prot[1] |= MT_PROT_RATE_CCK_11; + vht_prot[2] |= MT_PROT_RATE_CCK_11; + } else { + if (rts_thr != 0xffff) + prot[1] |= MT_PROT_CTRL_RTS_CTS; + + prot[2] |= MT_PROT_RATE_OFDM_24; + prot[3] |= MT_PROT_RATE_DUP_OFDM_24; + prot[4] |= MT_PROT_RATE_OFDM_24; + prot[5] |= MT_PROT_RATE_DUP_OFDM_24; + + vht_prot[0] |= MT_PROT_RATE_OFDM_24; + vht_prot[1] |= MT_PROT_RATE_DUP_OFDM_24; + vht_prot[2] |= MT_PROT_RATE_SGI_OFDM_24; + } + + switch (mode) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + prot[2] |= MT_PROT_CTRL_RTS_CTS; + prot[3] |= MT_PROT_CTRL_RTS_CTS; + prot[4] |= MT_PROT_CTRL_RTS_CTS; + prot[5] |= MT_PROT_CTRL_RTS_CTS; + vht_prot[0] |= MT_PROT_CTRL_RTS_CTS; + vht_prot[1] |= MT_PROT_CTRL_RTS_CTS; + vht_prot[2] |= MT_PROT_CTRL_RTS_CTS; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + prot[3] |= MT_PROT_CTRL_RTS_CTS; + prot[5] |= MT_PROT_CTRL_RTS_CTS; + vht_prot[1] |= MT_PROT_CTRL_RTS_CTS; + vht_prot[2] |= MT_PROT_CTRL_RTS_CTS; + break; + } + + if (non_gf) { + prot[4] |= MT_PROT_CTRL_RTS_CTS; + prot[5] |= MT_PROT_CTRL_RTS_CTS; + } + + for (i = 0; i < ARRAY_SIZE(prot); i++) + mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); + + for (i = 0; i < ARRAY_SIZE(vht_prot); i++) + mt76_wr(dev, MT_TX_PROT_CFG6 + i * 4, vht_prot[i]); +} + void mt76x02_update_channel(struct mt76_dev *mdev) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index d1a8ed171537..91c76a050f7e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -194,6 +194,8 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, struct mt76x02_tx_status *stat, u8 *update); int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, void *rxi); +void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot, + int ht_mode); void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val); void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr); void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index d1ac847adce5..20ad07638699 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -443,6 +443,7 @@ #define MT_PROT_RATE_OFDM_6 0x2000 #define MT_PROT_RATE_OFDM_24 0x2004 #define MT_PROT_RATE_DUP_OFDM_24 0x2084 +#define MT_PROT_RATE_SGI_OFDM_24 0x2104 #define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20) #define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \ ~MT_PROT_TXOP_ALLOW_MM40 & \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 364e7b2ebf99..aac64d0969b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -661,6 +661,10 @@ void mt76x02_bss_info_changed(struct ieee80211_hw *hw, tasklet_enable(&dev->pre_tbtt_tasklet); } + if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) + mt76x02_mac_set_tx_protection(dev, info->use_cts_prot, + info->ht_operation_mode); + if (changed & BSS_CHANGED_BEACON_INT) { mt76_rmw_field(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_INTVAL, -- cgit v1.2.3 From 9bc29420d745e775d36d224e4a6999ee77a600e1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 10 Dec 2018 11:53:58 +0100 Subject: mt76x0: configure MT_VHT_HT_FBK_CFG1 Configure MT_VHT_HT_FBK_CFG1 values similar like vendor driver. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h index a1657922758e..0290ba5869a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h @@ -88,6 +88,7 @@ static const struct mt76_reg_pair mt76x0_mac_reg_table[] = { { MT_TX_PROT_CFG6, 0xe3f42004 }, { MT_TX_PROT_CFG7, 0xe3f42084 }, { MT_TX_PROT_CFG8, 0xe3f42104 }, + { MT_VHT_HT_FBK_CFG1, 0xedcba980 }, }; static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = { -- cgit v1.2.3 From bf349ce16ef45bf5a0290586124be18a09826860 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 10 Dec 2018 12:54:05 +0100 Subject: mt76x2: add static qualifier to mt76x2_init_hardware Add static qualifier to mt76x2_init_hardware routine since it is used just in pci_init.c Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index b259e4b50f1e..28ec19acf9db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -53,7 +53,6 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev); int mt76x2_register_device(struct mt76x02_dev *dev); void mt76x2_phy_power_on(struct mt76x02_dev *dev); -int mt76x2_init_hardware(struct mt76x02_dev *dev); void mt76x2_stop_hardware(struct mt76x02_dev *dev); int mt76x2_eeprom_init(struct mt76x02_dev *dev); int mt76x2_apply_calibration_data(struct mt76x02_dev *dev, int channel); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 7f4ea2d00f42..2f05eacb8946 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -260,7 +260,7 @@ mt76x2_power_on(struct mt76x02_dev *dev) mt76x2_power_on_rf(dev, 1); } -int mt76x2_init_hardware(struct mt76x02_dev *dev) +static int mt76x2_init_hardware(struct mt76x02_dev *dev) { int ret; -- cgit v1.2.3 From 35c572818ca2a1d9bd3a76eab6366b9a299f0a0b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 12 Dec 2018 22:51:53 +0100 Subject: mt76: dfs: run mt76x02_dfs_set_domain atomically Grab mt76_dev mutex in mt76x02_dfs_set_domain since it runs concurrently with mt76x{0,2}_set_channel routines Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c index 054609c634a2..5bd523b091b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c @@ -881,12 +881,14 @@ mt76x02_dfs_set_domain(struct mt76x02_dev *dev, { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + mutex_lock(&dev->mt76.mutex); if (dfs_pd->region != region) { tasklet_disable(&dfs_pd->dfs_tasklet); dfs_pd->region = region; mt76x02_dfs_init_params(dev); tasklet_enable(&dfs_pd->dfs_tasklet); } + mutex_unlock(&dev->mt76.mutex); } void mt76x02_regd_notifier(struct wiphy *wiphy, -- cgit v1.2.3 From 3fd612df8ac79d8ac902985cb570f1723a82e979 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 12 Dec 2018 22:51:54 +0100 Subject: mt76x2: init: set default value for MT_TX_LINK_CFG Update default value for MT_TX_LINK_CFG according to vendor driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/init.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c index 54a9b5fac787..f8534362e2c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c @@ -143,6 +143,7 @@ void mt76_write_mac_initvals(struct mt76x02_dev *dev) { MT_VHT_HT_FBK_CFG1, 0xedcba980 }, { MT_PROT_AUTO_TX_CFG, 0x00830083 }, { MT_HT_CTRL_CFG, 0x000001ff }, + { MT_TX_LINK_CFG, 0x00001020 }, }; struct mt76_reg_pair prot_vals[] = { { MT_CCK_PROT_CFG, DEFAULT_PROT_CFG_CCK }, -- cgit v1.2.3 From f82ce8d9bd49ed1c3487662c734badfbf560cfe0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 12 Dec 2018 22:51:55 +0100 Subject: mt76: add energy detect CCA support to mt76x{0,2}e drivers Ported from the reference driver. Should fix compliance with ETSI regulatories on preventing transmission while energy detect values are above the threshold. The code has been tested using an ath9k device running tx99 as noise generator Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 2 + drivers/net/wireless/mediatek/mt76/mt76x02.h | 6 ++ drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c | 4 + drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 85 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 2 + drivers/net/wireless/mediatek/mt76/mt76x02_regs.h | 8 ++ .../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 1 + .../net/wireless/mediatek/mt76/mt76x2/pci_phy.c | 2 + 9 files changed, 111 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 1906cc62690f..720b05e325a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -147,6 +147,7 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) MT_CH_TIME_CFG_RX_AS_BUSY | MT_CH_TIME_CFG_NAV_AS_BUSY | MT_CH_TIME_CFG_EIFS_AS_BUSY | + MT_CH_CCA_RC_EN | FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); err = mt76x0_register_device(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 1eb1a802ed20..b2b38b9fcac7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -1013,6 +1013,8 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, mt76x0_phy_calibrate(dev, false); mt76x0_phy_set_txpower(dev); + mt76x02_edcca_init(dev); + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 6782665049dd..f383fdd914c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -101,6 +101,12 @@ struct mt76x02_dev { u8 slottime; struct mt76x02_dfs_pattern_detector dfs_pd; + + /* edcca monitor */ + bool ed_tx_blocked; + bool ed_monitor; + u8 ed_trigger; + u8 ed_silent; }; extern struct ieee80211_rate mt76x02_rates[12]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c index 5bd523b091b6..19fdcab746a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c @@ -884,6 +884,10 @@ mt76x02_dfs_set_domain(struct mt76x02_dev *dev, mutex_lock(&dev->mt76.mutex); if (dfs_pd->region != region) { tasklet_disable(&dfs_pd->dfs_tasklet); + + dev->ed_monitor = region == NL80211_DFS_ETSI; + mt76x02_edcca_init(dev); + dfs_pd->region = region; mt76x02_dfs_init_params(dev); tasklet_enable(&dfs_pd->dfs_tasklet); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index ddc1c3146feb..2e06e1f41810 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -847,6 +847,88 @@ static void mt76x02_check_mac_err(struct mt76x02_dev *dev) MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); } +static void +mt76x02_edcca_tx_enable(struct mt76x02_dev *dev, bool enable) +{ + if (enable) { + u32 data; + + mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN); + /* enable pa-lna */ + data = mt76_rr(dev, MT_TX_PIN_CFG); + data |= MT_TX_PIN_CFG_TXANT | + MT_TX_PIN_CFG_RXANT | + MT_TX_PIN_RFTR_EN | + MT_TX_PIN_TRSW_EN; + mt76_wr(dev, MT_TX_PIN_CFG, data); + } else { + mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN); + /* disable pa-lna */ + mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT); + mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_RXANT); + } + dev->ed_tx_blocked = !enable; +} + +void mt76x02_edcca_init(struct mt76x02_dev *dev) +{ + dev->ed_trigger = 0; + dev->ed_silent = 0; + + if (dev->ed_monitor) { + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + u8 ed_th = chan->band == NL80211_BAND_5GHZ ? 0x0e : 0x20; + + mt76_clear(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN); + mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); + mt76_rmw(dev, MT_BBP(AGC, 2), GENMASK(15, 0), + ed_th << 8 | ed_th); + if (!is_mt76x2(dev)) + mt76_set(dev, MT_TXOP_HLDR_ET, + MT_TXOP_HLDR_TX40M_BLK_EN); + } else { + mt76_set(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN); + mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); + if (is_mt76x2(dev)) { + mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); + } else { + mt76_wr(dev, MT_BBP(AGC, 2), 0x003a6464); + mt76_clear(dev, MT_TXOP_HLDR_ET, + MT_TXOP_HLDR_TX40M_BLK_EN); + } + } + mt76x02_edcca_tx_enable(dev, true); +} +EXPORT_SYMBOL_GPL(mt76x02_edcca_init); + +#define MT_EDCCA_TH 90 +#define MT_EDCCA_BLOCK_TH 2 +static void mt76x02_edcca_check(struct mt76x02_dev *dev) +{ + u32 val, busy; + + val = mt76_rr(dev, MT_ED_CCA_TIMER); + busy = (val * 100) / jiffies_to_usecs(MT_CALIBRATE_INTERVAL); + busy = min_t(u32, busy, 100); + + if (busy > MT_EDCCA_TH) { + dev->ed_trigger++; + dev->ed_silent = 0; + } else { + dev->ed_silent++; + dev->ed_trigger = 0; + } + + if (dev->ed_trigger > MT_EDCCA_BLOCK_TH && + !dev->ed_tx_blocked) + mt76x02_edcca_tx_enable(dev, false); + else if (dev->ed_silent > MT_EDCCA_BLOCK_TH && + dev->ed_tx_blocked) + mt76x02_edcca_tx_enable(dev, true); +} + void mt76x02_mac_work(struct work_struct *work) { struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, @@ -867,6 +949,9 @@ void mt76x02_mac_work(struct work_struct *work) if (!dev->beacon_mask) mt76x02_check_mac_err(dev); + if (dev->ed_monitor) + mt76x02_edcca_check(dev); + mutex_unlock(&dev->mt76.mutex); mt76_tx_status_check(&dev->mt76, NULL, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 91c76a050f7e..735fe96440ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -212,4 +212,6 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, bool val); + +void mt76x02_edcca_init(struct mt76x02_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index 20ad07638699..b8d1ffbac6b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -318,6 +318,7 @@ #define MT_CH_TIME_CFG_NAV_AS_BUSY BIT(3) #define MT_CH_TIME_CFG_EIFS_AS_BUSY BIT(4) #define MT_CH_TIME_CFG_MDRDY_CNT_EN BIT(5) +#define MT_CH_CCA_RC_EN BIT(6) #define MT_CH_TIME_CFG_CH_TIMER_CLR GENMASK(9, 8) #define MT_CH_TIME_CFG_MDRDY_CLR GENMASK(11, 10) @@ -378,6 +379,9 @@ #define MT_TX_PWR_CFG_4 0x1324 #define MT_TX_PIN_CFG 0x1328 #define MT_TX_PIN_CFG_TXANT GENMASK(3, 0) +#define MT_TX_PIN_CFG_RXANT GENMASK(11, 8) +#define MT_TX_PIN_RFTR_EN BIT(16) +#define MT_TX_PIN_TRSW_EN BIT(18) #define MT_TX_BAND_CFG 0x132c #define MT_TX_BAND_CFG_UPPER_40M BIT(0) @@ -398,6 +402,7 @@ #define MT_TXOP_CTRL_CFG 0x1340 #define MT_TXOP_TRUN_EN GENMASK(5, 0) #define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8) +#define MT_TXOP_ED_CCA_EN BIT(20) #define MT_TX_RTS_CFG 0x1344 #define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0) @@ -409,6 +414,7 @@ #define MT_TX_RETRY_CFG 0x134c #define MT_TX_LINK_CFG 0x1350 +#define MT_TX_CFACK_EN BIT(12) #define MT_VHT_HT_FBK_CFG0 0x1354 #define MT_VHT_HT_FBK_CFG1 0x1358 #define MT_LG_FBK_CFG0 0x135c @@ -512,6 +518,7 @@ #define MT_RX_FILTR_CFG_CTRL_RSV BIT(16) #define MT_AUTO_RSP_CFG 0x1404 +#define MT_AUTO_RSP_EN BIT(0) #define MT_AUTO_RSP_PREAMB_SHORT BIT(4) #define MT_LEGACY_BASIC_RATE 0x1408 #define MT_HT_BASIC_RATE 0x140c @@ -533,6 +540,7 @@ #define MT_PN_PAD_MODE 0x150c #define MT_TXOP_HLDR_ET 0x1608 +#define MT_TXOP_HLDR_TX40M_BLK_EN BIT(1) #define MT_PROT_AUTO_TX_CFG 0x1648 #define MT_PROT_AUTO_TX_CFG_PROT_PADJ GENMASK(11, 8) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 2f05eacb8946..9f313824eead 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -151,6 +151,7 @@ static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) MT_CH_TIME_CFG_RX_AS_BUSY | MT_CH_TIME_CFG_NAV_AS_BUSY | MT_CH_TIME_CFG_EIFS_AS_BUSY | + MT_CH_CCA_RC_EN | FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); mt76x02_set_tx_ackto(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index da7cd40f56ff..65ed62229a5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -254,6 +254,8 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, 0x38); } + mt76x02_edcca_init(dev); + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, MT_CALIBRATE_INTERVAL); -- cgit v1.2.3 From c09f4d0a1f81720342d4d0e1d4a2b601903f132a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Dec 2018 11:00:47 +0100 Subject: mt76: mac: minor optimizations in mt76x02_mac_tx_rate_val Do not set bw variable to zero for legacy rates since it is already initialized to zero. Moreover set nss to 1 just for legacy rates since nss will be properly set for VHT/HT rates Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 2e06e1f41810..cc584ea4a8d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -130,10 +130,8 @@ static __le16 mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val) { + u8 phy, rate_idx, nss, bw = 0; u16 rateval; - u8 phy, rate_idx; - u8 nss = 1; - u8 bw = 0; if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { rate_idx = rate->idx; @@ -164,7 +162,7 @@ mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev, phy = val >> 8; rate_idx = val & 0xff; - bw = 0; + nss = 1; } rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx); -- cgit v1.2.3 From 87e86f90196fa074f8f6ac0e77d1287d9239878b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 3 Dec 2018 15:34:24 +0100 Subject: mt76: dma: do not build skb if reported len does not fit in buf_size Precompute data length in order to avoid to allocate the related skb data structure if reported length does not fit in queue buf_size Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index b7fd2e110663..1db163c40dcf 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -417,10 +417,9 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data, static int mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) { + int len, data_len, done = 0; struct sk_buff *skb; unsigned char *data; - int len; - int done = 0; bool more; while (done < budget) { @@ -430,7 +429,12 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) if (!data) break; - if (q->buf_size < len + q->buf_offset) { + if (q->rx_head) + data_len = q->buf_size; + else + data_len = SKB_WITH_OVERHEAD(q->buf_size); + + if (data_len < len + q->buf_offset) { dev_kfree_skb(q->rx_head); q->rx_head = NULL; @@ -448,12 +452,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) skb_free_frag(data); continue; } - skb_reserve(skb, q->buf_offset); - if (skb->tail + len > skb->end) { - dev_kfree_skb(skb); - continue; - } if (q == &dev->q_rx[MT_RXQ_MCU]) { u32 *rxfce = (u32 *) skb->cb; -- cgit v1.2.3 From c1e0d2be0acff5e99a59ddcc5af415e48abc6c5e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Dec 2018 15:44:09 +0100 Subject: mt76: mmio: introduce mt76x02_check_tx_hang watchdog Port mt76x02_check_tx_hang watchdog from vendor driver in order to perform a device reset when tx mac/dma logic hangs. Tx mac/dma stuck has been observed when the device is heavy loaded or in a noisy environment. Moreover introduce wdt delayed work in order to run tx_hang watchdog. For the moment run mt76x02_check_tx_hang watchdog just on mt76x2 devices since the issue has not been observed on mt76x0 driver yet Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x02.h | 8 ++ .../net/wireless/mediatek/mt76/mt76x02_debugfs.c | 2 + drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 124 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 + .../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 1 + .../net/wireless/mediatek/mt76/mt76x2/pci_main.c | 2 + 8 files changed, 140 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 5cd508a68609..8ef430d8afc4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -421,6 +421,7 @@ struct mt76_dev { struct mt76_queue q_tx[__MT_TXQ_MAX]; struct mt76_queue q_rx[__MT_RXQ_MAX]; const struct mt76_queue_ops *queue_ops; + int tx_dma_idx[4]; wait_queue_head_t tx_wait; struct sk_buff_head status_list; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index f383fdd914c5..f594e8c82500 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -28,6 +28,9 @@ #define MT_CALIBRATE_INTERVAL HZ +#define MT_WATCHDOG_TIME (HZ / 10) +#define MT_TX_HANG_TH 10 + #define MT_MAX_CHAINS 2 struct mt76x02_rx_freq_cal { s8 high_gain[MT_MAX_CHAINS]; @@ -79,6 +82,7 @@ struct mt76x02_dev { struct tasklet_struct pre_tbtt_tasklet; struct delayed_work cal_work; struct delayed_work mac_work; + struct delayed_work wdt_work; u32 aggr_stats[32]; @@ -89,6 +93,9 @@ struct mt76x02_dev { u8 tbtt_count; u16 beacon_int; + u32 tx_hang_reset; + u8 tx_hang_check; + struct mt76x02_calibration cal; s8 target_power; @@ -142,6 +149,7 @@ s8 mt76x02_tx_get_max_txpwr_adj(struct mt76x02_dev *dev, const struct ieee80211_tx_rate *rate); s8 mt76x02_tx_get_txpwr_adj(struct mt76x02_dev *dev, s8 txpwr, s8 max_txpwr_adj); +void mt76x02_wdt_work(struct work_struct *work); void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); void mt76x02_set_tx_ackto(struct mt76x02_dev *dev); void mt76x02_set_coverage_class(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c index a9d52ba1e270..7580c5c986ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c @@ -133,5 +133,7 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev) read_txpower); debugfs_create_devm_seqfile(dev->mt76.dev, "agc", dir, read_agc); + + debugfs_create_u32("tx_hang_reset", 0400, dir, &dev->tx_hang_reset); } EXPORT_SYMBOL_GPL(mt76x02_init_debugfs); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index cc584ea4a8d7..6adea0278284 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -943,7 +943,6 @@ void mt76x02_mac_work(struct work_struct *work) dev->aggr_stats[idx++] += val >> 16; } - /* XXX: check beacon stuck for ap mode */ if (!dev->beacon_mask) mt76x02_check_mac_err(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 6974acc75e2b..6236c6121c01 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -385,3 +385,127 @@ void mt76x02_mac_start(struct mt76x02_dev *dev) MT_INT_TX_STAT); } EXPORT_SYMBOL_GPL(mt76x02_mac_start); + +static bool mt76x02_tx_hang(struct mt76x02_dev *dev) +{ + u32 dma_idx, prev_dma_idx; + struct mt76_queue *q; + int i; + + for (i = 0; i < 4; i++) { + q = &dev->mt76.q_tx[i]; + + if (!q->queued) + continue; + + prev_dma_idx = dev->mt76.tx_dma_idx[i]; + dma_idx = ioread32(&q->regs->dma_idx); + dev->mt76.tx_dma_idx[i] = dma_idx; + + if (prev_dma_idx == dma_idx) + break; + } + + return i < 4; +} + +static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) +{ + u32 mask = dev->mt76.mmio.irqmask; + int i; + + ieee80211_stop_queues(dev->mt76.hw); + set_bit(MT76_RESET, &dev->mt76.state); + + tasklet_disable(&dev->pre_tbtt_tasklet); + tasklet_disable(&dev->tx_tasklet); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++) + napi_disable(&dev->mt76.napi[i]); + + mutex_lock(&dev->mt76.mutex); + + if (dev->beacon_mask) + mt76_clear(dev, MT_BEACON_TIME_CFG, + MT_BEACON_TIME_CFG_BEACON_TX | + MT_BEACON_TIME_CFG_TBTT_EN); + + mt76x02_irq_disable(dev, mask); + + /* perform device reset */ + mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); + mt76_wr(dev, MT_MAC_SYS_CTRL, 0); + mt76_clear(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN); + usleep_range(5000, 10000); + mt76_wr(dev, MT_INT_SOURCE_CSR, 0xffffffff); + + /* let fw reset DMA */ + mt76_set(dev, 0x734, 0x3); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.q_tx); i++) + mt76_queue_tx_cleanup(dev, i, true); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.q_rx); i++) + mt76_queue_rx_reset(dev, i); + + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); + mt76_set(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN); + if (dev->ed_monitor) + mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); + + if (dev->beacon_mask) + mt76_set(dev, MT_BEACON_TIME_CFG, + MT_BEACON_TIME_CFG_BEACON_TX | + MT_BEACON_TIME_CFG_TBTT_EN); + + mt76x02_irq_enable(dev, mask); + + mutex_unlock(&dev->mt76.mutex); + + clear_bit(MT76_RESET, &dev->mt76.state); + + tasklet_enable(&dev->tx_tasklet); + tasklet_schedule(&dev->tx_tasklet); + + tasklet_enable(&dev->pre_tbtt_tasklet); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++) { + napi_enable(&dev->mt76.napi[i]); + napi_schedule(&dev->mt76.napi[i]); + } + + ieee80211_wake_queues(dev->mt76.hw); + + mt76_txq_schedule_all(&dev->mt76); +} + +static void mt76x02_check_tx_hang(struct mt76x02_dev *dev) +{ + if (mt76x02_tx_hang(dev)) { + if (++dev->tx_hang_check < MT_TX_HANG_TH) + return; + + mt76x02_watchdog_reset(dev); + + dev->tx_hang_reset++; + dev->tx_hang_check = 0; + memset(dev->mt76.tx_dma_idx, 0xff, + sizeof(dev->mt76.tx_dma_idx)); + } else { + dev->tx_hang_check = 0; + } +} + +void mt76x02_wdt_work(struct work_struct *work) +{ + struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, + wdt_work.work); + + mt76x02_check_tx_hang(dev); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work, + MT_WATCHDOG_TIME); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index aac64d0969b8..3c878f18e05d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -93,6 +93,8 @@ void mt76x02_init_device(struct mt76x02_dev *dev) MT_DMA_HDR_LEN; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); } else { + INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work); + mt76x02_dfs_init_detector(dev); wiphy->reg_notifier = mt76x02_regd_notifier; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 9f313824eead..34418e575542 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -301,6 +301,7 @@ void mt76x2_stop_hardware(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); + cancel_delayed_work_sync(&dev->wdt_work); mt76x02_mcu_set_radio_state(dev, false); mt76x2_mac_stop(dev, false); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index b54a32397486..6a87b88eb036 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -34,6 +34,8 @@ mt76x2_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, MT_CALIBRATE_INTERVAL); + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work, + MT_WATCHDOG_TIME); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); -- cgit v1.2.3 From 32fb47fd9c5553ab77ad0380e1ac421d7b3ac564 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 30 Dec 2018 13:26:40 +0000 Subject: mt76: make const array 'data' static, shrinks object size Don't populate the const array 'data' on the stack but instead make it static. Makes the object code smaller by 78 bytes: Before: text data bss dec hex filename 5438 1080 0 6518 1976 mediatek/mt76/mt76x2/usb_mcu.o After: text data bss dec hex filename 5296 1144 0 6440 1928 mediatek/mt76/mt76x2/usb_mcu.o (gcc version 8.2.0 x86_64) Signed-off-by: Colin Ian King Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c index 45a95ee3a415..152d41fe9ff5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c @@ -39,7 +39,7 @@ static void mt76x2u_mcu_load_ivb(struct mt76x02_dev *dev) static void mt76x2u_mcu_enable_patch(struct mt76x02_dev *dev) { struct mt76_usb *usb = &dev->mt76.usb; - const u8 data[] = { + static const u8 data[] = { 0x6f, 0xfc, 0x08, 0x01, 0x20, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, -- cgit v1.2.3 From e76deac6f00bd855215454228fbb70f2f5f0eea4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 31 Dec 2018 15:42:54 +0100 Subject: mt76: dma: avoid indirect call in mt76_dma_tx_queue_skb Call mt76_dma_add_buf routine directly in mt76_dma_tx_queue_skb and avoid indirect call if not necessary Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 1db163c40dcf..e769c8a555dd 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -300,7 +300,7 @@ int mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, if (q->queued + (n + 1) / 2 >= q->ndesc - 1) goto unmap; - return dev->queue_ops->add_buf(dev, q, buf, n, tx_info, skb, t); + return mt76_dma_add_buf(dev, q, buf, n, tx_info, skb, t); unmap: ret = -ENOMEM; -- cgit v1.2.3 From 3121742915b552f1994775f9d34512ccc0a82e66 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 10 Jan 2019 12:14:04 +0100 Subject: mt76: use proper name for __MT76x02_H macro Use proper name for __MT76x02_H macro in mt76x02.h Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index f594e8c82500..d8bd0509a790 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -15,8 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef __MT76X02_UTIL_H -#define __MT76X02_UTIL_H +#ifndef __MT76x02_H +#define __MT76x02_H #include @@ -238,4 +238,4 @@ mt76x02_rx_get_sta_wcid(struct mt76x02_sta *sta, bool unicast) return &sta->vif->group_wcid; } -#endif +#endif /* __MT76x02_H */ -- cgit v1.2.3 From 5c9decdfbb409d3c410c3e2308cb6110557eb0a7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 10 Jan 2019 14:27:06 +0100 Subject: mt76: add led support to mt76x0e driver Move mt76x02 led support in mt76x02-lib module in order to add tpt led trigger to mt76x0e driver Tested-by: LGA1150 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_regs.h | 23 +++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 59 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h | 23 --------- .../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 54 -------------------- 4 files changed, 82 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index b8d1ffbac6b5..7401cb94fb72 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -230,6 +230,29 @@ #define MT_COM_REG2 0x0738 #define MT_COM_REG3 0x073C +#define MT_LED_CTRL 0x0770 +#define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) +#define MT_LED_CTRL_POLARITY(_n) BIT(1 + (8 * (_n))) +#define MT_LED_CTRL_TX_BLINK_MODE(_n) BIT(2 + (8 * (_n))) +#define MT_LED_CTRL_KICK(_n) BIT(7 + (8 * (_n))) + +#define MT_LED_TX_BLINK_0 0x0774 +#define MT_LED_TX_BLINK_1 0x0778 + +#define MT_LED_S0_BASE 0x077C +#define MT_LED_S0(_n) (MT_LED_S0_BASE + 8 * (_n)) +#define MT_LED_S1_BASE 0x0780 +#define MT_LED_S1(_n) (MT_LED_S1_BASE + 8 * (_n)) +#define MT_LED_STATUS_OFF_MASK GENMASK(31, 24) +#define MT_LED_STATUS_OFF(_v) (((_v) << __ffs(MT_LED_STATUS_OFF_MASK)) & \ + MT_LED_STATUS_OFF_MASK) +#define MT_LED_STATUS_ON_MASK GENMASK(23, 16) +#define MT_LED_STATUS_ON(_v) (((_v) << __ffs(MT_LED_STATUS_ON_MASK)) & \ + MT_LED_STATUS_ON_MASK) +#define MT_LED_STATUS_DURATION_MASK GENMASK(15, 8) +#define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \ + MT_LED_STATUS_DURATION_MASK) + #define MT_FCE_PSE_CTRL 0x0800 #define MT_FCE_PARAMETERS 0x0804 #define MT_FCE_CSO 0x0808 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 3c878f18e05d..d80c8eb5a0ec 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -75,6 +75,58 @@ static const struct ieee80211_iface_combination mt76x02_if_comb[] = { } }; +static void +mt76x02_led_set_config(struct mt76_dev *mdev, u8 delay_on, + u8 delay_off) +{ + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, + mt76); + u32 val; + + val = MT_LED_STATUS_DURATION(0xff) | + MT_LED_STATUS_OFF(delay_off) | + MT_LED_STATUS_ON(delay_on); + + mt76_wr(dev, MT_LED_S0(mdev->led_pin), val); + mt76_wr(dev, MT_LED_S1(mdev->led_pin), val); + + val = MT_LED_CTRL_REPLAY(mdev->led_pin) | + MT_LED_CTRL_KICK(mdev->led_pin); + if (mdev->led_al) + val |= MT_LED_CTRL_POLARITY(mdev->led_pin); + mt76_wr(dev, MT_LED_CTRL, val); +} + +static int +mt76x02_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mt76_dev *mdev = container_of(led_cdev, struct mt76_dev, + led_cdev); + u8 delta_on, delta_off; + + delta_off = max_t(u8, *delay_off / 10, 1); + delta_on = max_t(u8, *delay_on / 10, 1); + + mt76x02_led_set_config(mdev, delta_on, delta_off); + + return 0; +} + +static void +mt76x02_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct mt76_dev *mdev = container_of(led_cdev, struct mt76_dev, + led_cdev); + + if (!brightness) + mt76x02_led_set_config(mdev, 0, 0xff); + else + mt76x02_led_set_config(mdev, 0xff, 0); +} + void mt76x02_init_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); @@ -109,6 +161,13 @@ void mt76x02_init_device(struct mt76x02_dev *dev) BIT(NL80211_IFTYPE_ADHOC); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + + /* init led callbacks */ + if (IS_ENABLED(CONFIG_MT76_LEDS)) { + dev->mt76.led_cdev.brightness_set = + mt76x02_led_set_brightness; + dev->mt76.led_cdev.blink_set = mt76x02_led_set_blink; + } } hw->sta_data_size = sizeof(struct mt76x02_sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h index acfa2b570c7c..40ef43926c06 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h @@ -26,29 +26,6 @@ #define MT_MCU_PCIE_REMAP_BASE2 0x0744 #define MT_MCU_PCIE_REMAP_BASE3 0x0748 -#define MT_LED_CTRL 0x0770 -#define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) -#define MT_LED_CTRL_POLARITY(_n) BIT(1 + (8 * (_n))) -#define MT_LED_CTRL_TX_BLINK_MODE(_n) BIT(2 + (8 * (_n))) -#define MT_LED_CTRL_KICK(_n) BIT(7 + (8 * (_n))) - -#define MT_LED_TX_BLINK_0 0x0774 -#define MT_LED_TX_BLINK_1 0x0778 - -#define MT_LED_S0_BASE 0x077C -#define MT_LED_S0(_n) (MT_LED_S0_BASE + 8 * (_n)) -#define MT_LED_S1_BASE 0x0780 -#define MT_LED_S1(_n) (MT_LED_S1_BASE + 8 * (_n)) -#define MT_LED_STATUS_OFF_MASK GENMASK(31, 24) -#define MT_LED_STATUS_OFF(_v) (((_v) << __ffs(MT_LED_STATUS_OFF_MASK)) & \ - MT_LED_STATUS_OFF_MASK) -#define MT_LED_STATUS_ON_MASK GENMASK(23, 16) -#define MT_LED_STATUS_ON(_v) (((_v) << __ffs(MT_LED_STATUS_ON_MASK)) & \ - MT_LED_STATUS_ON_MASK) -#define MT_LED_STATUS_DURATION_MASK GENMASK(15, 8) -#define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \ - MT_LED_STATUS_DURATION_MASK) - #define MT_MCU_ROM_PATCH_OFFSET 0x80000 #define MT_MCU_ROM_PATCH_ADDR 0x90000 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 34418e575542..4347d5e7a915 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -342,54 +342,6 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) return dev; } -static void mt76x2_led_set_config(struct mt76_dev *mt76, u8 delay_on, - u8 delay_off) -{ - struct mt76x02_dev *dev = container_of(mt76, struct mt76x02_dev, - mt76); - u32 val; - - val = MT_LED_STATUS_DURATION(0xff) | - MT_LED_STATUS_OFF(delay_off) | - MT_LED_STATUS_ON(delay_on); - - mt76_wr(dev, MT_LED_S0(mt76->led_pin), val); - mt76_wr(dev, MT_LED_S1(mt76->led_pin), val); - - val = MT_LED_CTRL_REPLAY(mt76->led_pin) | - MT_LED_CTRL_KICK(mt76->led_pin); - if (mt76->led_al) - val |= MT_LED_CTRL_POLARITY(mt76->led_pin); - mt76_wr(dev, MT_LED_CTRL, val); -} - -static int mt76x2_led_set_blink(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off) -{ - struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, - led_cdev); - u8 delta_on, delta_off; - - delta_off = max_t(u8, *delay_off / 10, 1); - delta_on = max_t(u8, *delay_on / 10, 1); - - mt76x2_led_set_config(mt76, delta_on, delta_off); - return 0; -} - -static void mt76x2_led_set_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, - led_cdev); - - if (!brightness) - mt76x2_led_set_config(mt76, 0, 0xff); - else - mt76x2_led_set_config(mt76, 0xff, 0); -} - int mt76x2_register_device(struct mt76x02_dev *dev) { int ret; @@ -404,12 +356,6 @@ int mt76x2_register_device(struct mt76x02_dev *dev) mt76x02_config_mac_addr_list(dev); - /* init led callbacks */ - if (IS_ENABLED(CONFIG_MT76_LEDS)) { - dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness; - dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink; - } - ret = mt76_register_device(&dev->mt76, true, mt76x02_rates, ARRAY_SIZE(mt76x02_rates)); if (ret) -- cgit v1.2.3 From 11c8bac9b3877fb8d8b4674f4744c1b5937956ba Mon Sep 17 00:00:00 2001 From: Roy Pledge Date: Mon, 10 Dec 2018 16:50:17 +0000 Subject: soc: fsl: dpio: perform DPIO Reset on Probe Invoke a DPIO reset command when a DPIO device is probed. This will ensure the QBMan portal is in the state the driver expects. Signed-off-by: Roy Pledge Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-cmd.h | 1 + drivers/soc/fsl/dpio/dpio-driver.c | 7 +++++++ drivers/soc/fsl/dpio/dpio.c | 23 +++++++++++++++++++++++ drivers/soc/fsl/dpio/dpio.h | 4 ++++ 4 files changed, 35 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/fsl/dpio/dpio-cmd.h b/drivers/soc/fsl/dpio/dpio-cmd.h index ab8f82ee7ee5..5814d2f395a4 100644 --- a/drivers/soc/fsl/dpio/dpio-cmd.h +++ b/drivers/soc/fsl/dpio/dpio-cmd.h @@ -25,6 +25,7 @@ #define DPIO_CMDID_ENABLE DPIO_CMD(0x002) #define DPIO_CMDID_DISABLE DPIO_CMD(0x003) #define DPIO_CMDID_GET_ATTR DPIO_CMD(0x004) +#define DPIO_CMDID_RESET DPIO_CMD(0x005) struct dpio_cmd_open { __le32 dpio_id; diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 832175cac739..38ee9dba1c96 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -110,6 +110,12 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) goto err_open; } + err = dpio_reset(dpio_dev->mc_io, 0, dpio_dev->mc_handle); + if (err) { + dev_err(dev, "dpio_reset() failed\n"); + goto err_reset; + } + err = dpio_get_attributes(dpio_dev->mc_io, 0, dpio_dev->mc_handle, &dpio_attrs); if (err) { @@ -192,6 +198,7 @@ err_register_dpio_irq: err_allocate_irqs: dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); err_get_attr: +err_reset: dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); err_open: fsl_mc_portal_free(dpio_dev->mc_io); diff --git a/drivers/soc/fsl/dpio/dpio.c b/drivers/soc/fsl/dpio/dpio.c index ff37c80e11a0..521bc6946317 100644 --- a/drivers/soc/fsl/dpio/dpio.c +++ b/drivers/soc/fsl/dpio/dpio.c @@ -196,3 +196,26 @@ int dpio_get_api_version(struct fsl_mc_io *mc_io, return 0; } + +/** + * dpio_reset() - Reset the DPIO, returns the object to initial state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPIO object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpio_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_RESET, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} diff --git a/drivers/soc/fsl/dpio/dpio.h b/drivers/soc/fsl/dpio/dpio.h index 49194c8e45f1..b2ac4ba4fb8e 100644 --- a/drivers/soc/fsl/dpio/dpio.h +++ b/drivers/soc/fsl/dpio/dpio.h @@ -80,4 +80,8 @@ int dpio_get_api_version(struct fsl_mc_io *mc_io, u16 *major_ver, u16 *minor_ver); +int dpio_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + #endif /* __FSL_DPIO_H */ -- cgit v1.2.3 From 9182ee2840a99d8f3bc7b4332fc93c03c2016fd6 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 10 Dec 2018 16:50:17 +0000 Subject: soc: fsl: dpio: keep a per dpio device MC portal At the moment, the dpio-driver allocates an MC portal at probe time and frees it right after usage. The same thing happens on the remove path. This behavior could lead to scenarios where an MC portal is available for use at probing but not longer free on the remove path which could lead to unproper unbind of resources. Change the driver's behavior in such a way that an MC portal is allocated at probe and kept until the DPIO device is removed. This will ensure that at any time after a DPIO device was successfully probed, all its dependencies will be met. Signed-off-by: Ioana Ciornei Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-driver.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 38ee9dba1c96..5286723d4a14 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -187,7 +187,6 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) dev_dbg(dev, " receives_notifications = %d\n", desc.receives_notifications); dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); - fsl_mc_portal_free(dpio_dev->mc_io); return 0; @@ -229,12 +228,6 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) cpu = dpaa2_io_get_cpu(priv->io); cpumask_set_cpu(cpu, cpus_unused_mask); - err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io); - if (err) { - dev_err(dev, "MC portal allocation failed\n"); - goto err_mcportal; - } - err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id, &dpio_dev->mc_handle); if (err) { @@ -252,7 +245,7 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) err_open: fsl_mc_portal_free(dpio_dev->mc_io); -err_mcportal: + return err; } -- cgit v1.2.3 From cf9ff75d15a9bbd625519997c2ca864d1fa80227 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 10 Dec 2018 16:50:18 +0000 Subject: soc: fsl: dpio: store a backpointer to the device backing the dpaa2_io Add a new field in the dpaa2_io structure to hold a backpointer to the actual DPIO device. Signed-off-by: Ioana Ciornei Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-driver.c | 2 +- drivers/soc/fsl/dpio/dpio-service.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 5286723d4a14..2d4af32a0dec 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -176,7 +176,7 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) if (err) goto err_register_dpio_irq; - priv->io = dpaa2_io_create(&desc); + priv->io = dpaa2_io_create(&desc, dev); if (!priv->io) { dev_err(dev, "dpaa2_io_create failed\n"); err = -ENOMEM; diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index c02bfb18a1f0..52d800aa4774 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -27,6 +27,7 @@ struct dpaa2_io { /* protect notifications list */ spinlock_t lock_notifications; struct list_head notifications; + struct device *dev; }; struct dpaa2_io_store { @@ -98,13 +99,15 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_select); /** * dpaa2_io_create() - create a dpaa2_io object. * @desc: the dpaa2_io descriptor + * @dev: the actual DPIO device * * Activates a "struct dpaa2_io" corresponding to the given config of an actual * DPIO object. * * Return a valid dpaa2_io object for success, or NULL for failure. */ -struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc) +struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc, + struct device *dev) { struct dpaa2_io *obj = kmalloc(sizeof(*obj), GFP_KERNEL); @@ -146,6 +149,8 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc) dpio_by_cpu[desc->cpu] = obj; spin_unlock(&dpio_list_lock); + obj->dev = dev; + return obj; } -- cgit v1.2.3 From f1e250bf365962519c96a1255b2fe34b6c0d6c60 Mon Sep 17 00:00:00 2001 From: Ioana Ciocoi Radulescu Date: Fri, 14 Dec 2018 16:04:05 +0000 Subject: soc: fsl: dpio: Add prefetch instruction In dpaa2_io_store_next(), if the current dequeue entry is not the last, prefetch the next one as most likely it will be requested shortly by the consumer driver. This brings a ~3% improvement for dpaa2 ethernet driver IP forwarding with small size frames. Signed-off-by: Ioana Radulescu Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-service.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index bc801934602a..5389336463c0 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -630,6 +630,7 @@ struct dpaa2_dq *dpaa2_io_store_next(struct dpaa2_io_store *s, int *is_last) if (!(dpaa2_dq_flags(ret) & DPAA2_DQ_STAT_VALIDFRAME)) ret = NULL; } else { + prefetch(&s->vaddr[s->idx]); *is_last = 0; } -- cgit v1.2.3 From 47441f7f73b7cf0c2d6e7d6372f026ea81193fd6 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 10 Dec 2018 16:50:19 +0000 Subject: soc: fsl: dpio: add a device_link at dpaa2_io_service_register Automatically add a device link between the actual device requesting the dpaa2_io_service_register and the underlying dpaa2_io used. This link will ensure that when a DPIO device, which is indirectly used by other devices, is unbound any consumer devices will be also unbound from their drivers. For example, any DPNI, bound to the dpaa2-eth driver, which is using DPIO devices will be unbound before its supplier device. Also, add a new parameter to the dpaa2_io_service_[de]register functions to specify the requesting device (ie the consumer). Signed-off-by: Ioana Ciornei Reviewed-by: Horia Geanta Reviewed-by: Ioana Radulescu Signed-off-by: Li Yang --- drivers/crypto/caam/caamalg_qi2.c | 6 +++--- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 9 +++++---- drivers/soc/fsl/dpio/dpio-service.c | 16 ++++++++++++++-- 3 files changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 425d5d974613..77f4c0045de2 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -4503,7 +4503,7 @@ static int __cold dpaa2_dpseci_dpio_setup(struct dpaa2_caam_priv *priv) nctx->cb = dpaa2_caam_fqdan_cb; /* Register notification callbacks */ - err = dpaa2_io_service_register(NULL, nctx); + err = dpaa2_io_service_register(NULL, nctx, dev); if (unlikely(err)) { dev_dbg(dev, "No affine DPIO for cpu %d\n", cpu); nctx->cb = NULL; @@ -4536,7 +4536,7 @@ err: ppriv = per_cpu_ptr(priv->ppriv, cpu); if (!ppriv->nctx.cb) break; - dpaa2_io_service_deregister(NULL, &ppriv->nctx); + dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev); } for_each_online_cpu(cpu) { @@ -4556,7 +4556,7 @@ static void __cold dpaa2_dpseci_dpio_free(struct dpaa2_caam_priv *priv) for_each_online_cpu(cpu) { ppriv = per_cpu_ptr(priv->ppriv, cpu); - dpaa2_io_service_deregister(NULL, &ppriv->nctx); + dpaa2_io_service_deregister(NULL, &ppriv->nctx, priv->dev); dpaa2_io_store_destroy(ppriv->store); if (++i == priv->num_pairs) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 1ca9a18139ec..c500ea77aaa0 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1902,7 +1902,7 @@ static int setup_dpio(struct dpaa2_eth_priv *priv) /* Register the new context */ channel->dpio = dpaa2_io_service_select(i); - err = dpaa2_io_service_register(channel->dpio, nctx); + err = dpaa2_io_service_register(channel->dpio, nctx, dev); if (err) { dev_dbg(dev, "No affine DPIO for cpu %d\n", i); /* If no affine DPIO for this core, there's probably @@ -1942,7 +1942,7 @@ static int setup_dpio(struct dpaa2_eth_priv *priv) return 0; err_set_cdan: - dpaa2_io_service_deregister(channel->dpio, nctx); + dpaa2_io_service_deregister(channel->dpio, nctx, dev); err_service_reg: free_channel(priv, channel); err_alloc_ch: @@ -1962,13 +1962,14 @@ err_alloc_ch: static void free_dpio(struct dpaa2_eth_priv *priv) { - int i; + struct device *dev = priv->net_dev->dev.parent; struct dpaa2_eth_channel *ch; + int i; /* deregister CDAN notifications and free channels */ for (i = 0; i < priv->num_channels; i++) { ch = priv->channel[i]; - dpaa2_io_service_deregister(ch->dpio, &ch->nctx); + dpaa2_io_service_deregister(ch->dpio, &ch->nctx, dev); free_channel(priv, ch); } } diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index 52d800aa4774..bc801934602a 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -237,6 +237,7 @@ EXPORT_SYMBOL(dpaa2_io_get_cpu); * notifications on the given DPIO service. * @d: the given DPIO service. * @ctx: the notification context. + * @dev: the device that requests the register * * The caller should make the MC command to attach a DPAA2 object to * a DPIO after this function completes successfully. In that way: @@ -251,14 +252,20 @@ EXPORT_SYMBOL(dpaa2_io_get_cpu); * Return 0 for success, or -ENODEV for failure. */ int dpaa2_io_service_register(struct dpaa2_io *d, - struct dpaa2_io_notification_ctx *ctx) + struct dpaa2_io_notification_ctx *ctx, + struct device *dev) { + struct device_link *link; unsigned long irqflags; d = service_select_by_cpu(d, ctx->desired_cpu); if (!d) return -ENODEV; + link = device_link_add(dev, d->dev, DL_FLAG_AUTOREMOVE_CONSUMER); + if (!link) + return -EINVAL; + ctx->dpio_id = d->dpio_desc.dpio_id; ctx->qman64 = (u64)(uintptr_t)ctx; ctx->dpio_private = d; @@ -279,12 +286,14 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_register); * dpaa2_io_service_deregister - The opposite of 'register'. * @service: the given DPIO service. * @ctx: the notification context. + * @dev: the device that requests to be deregistered * * This function should be called only after sending the MC command to * to detach the notification-producing device from the DPIO. */ void dpaa2_io_service_deregister(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx) + struct dpaa2_io_notification_ctx *ctx, + struct device *dev) { struct dpaa2_io *d = ctx->dpio_private; unsigned long irqflags; @@ -295,6 +304,9 @@ void dpaa2_io_service_deregister(struct dpaa2_io *service, spin_lock_irqsave(&d->lock_notifications, irqflags); list_del(&ctx->node); spin_unlock_irqrestore(&d->lock_notifications, irqflags); + + if (dev) + device_link_remove(dev, d->dev); } EXPORT_SYMBOL_GPL(dpaa2_io_service_deregister); -- cgit v1.2.3 From 8a533a7de21aa69cf9a3e55223c819858fbc7da2 Mon Sep 17 00:00:00 2001 From: Ioana Ciocoi Radulescu Date: Fri, 14 Dec 2018 16:04:06 +0000 Subject: soc: fsl: dpio: Change bpid type to u16 In all QBMan registers, the buffer pool id field is two bytes long. The low level qbman APIs reflect this, but the high level DPIO ones use u32. Modify them in order to avoid implicit downcasts. Signed-off-by: Ioana Radulescu Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-service.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index 5389336463c0..b9539ef2c3cd 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -473,7 +473,7 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_enqueue_qd); * Return 0 for success, and negative error code for failure. */ int dpaa2_io_service_release(struct dpaa2_io *d, - u32 bpid, + u16 bpid, const u64 *buffers, unsigned int num_buffers) { @@ -502,7 +502,7 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_release); * Eg. if the buffer pool is empty, this will return zero. */ int dpaa2_io_service_acquire(struct dpaa2_io *d, - u32 bpid, + u16 bpid, u64 *buffers, unsigned int num_buffers) { -- cgit v1.2.3 From afb77422819ff60612e9b7d36461b9b2bc8e038e Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 10 Dec 2018 16:50:19 +0000 Subject: bus: fsl-mc: automatically add a device_link on fsl_mc_[portal,object]_allocate Allocatable devices can be acquired by drivers on the fsl-mc bus using the fsl_mc_portal_allocate or fsl_mc_object_allocate functions. Add a device link between the consumer device and the supplier device so that proper resource management is achieved. Also, adding a link between these devices ensures that a proper unbind order is respected (ie before the supplier device is unbound from its respective driver all consumer devices will be notified and unbound first). Signed-off-by: Ioana Ciornei Reviewed-by: Laurentiu Tudor Signed-off-by: Li Yang --- drivers/bus/fsl-mc/fsl-mc-allocator.c | 11 +++++++++++ drivers/bus/fsl-mc/mc-io.c | 13 +++++++++++++ 2 files changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/bus/fsl-mc/fsl-mc-allocator.c b/drivers/bus/fsl-mc/fsl-mc-allocator.c index e906ecfe23dd..8ad77246f322 100644 --- a/drivers/bus/fsl-mc/fsl-mc-allocator.c +++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c @@ -295,6 +295,14 @@ int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, if (!mc_adev) goto error; + mc_adev->consumer_link = device_link_add(&mc_dev->dev, + &mc_adev->dev, + DL_FLAG_AUTOREMOVE_CONSUMER); + if (!mc_adev->consumer_link) { + error = -EINVAL; + goto error; + } + *new_mc_adev = mc_adev; return 0; error: @@ -321,6 +329,9 @@ void fsl_mc_object_free(struct fsl_mc_device *mc_adev) return; fsl_mc_resource_free(resource); + + device_link_del(mc_adev->consumer_link); + mc_adev->consumer_link = NULL; } EXPORT_SYMBOL_GPL(fsl_mc_object_free); diff --git a/drivers/bus/fsl-mc/mc-io.c b/drivers/bus/fsl-mc/mc-io.c index 7226cfc49b6f..3ae574a58cce 100644 --- a/drivers/bus/fsl-mc/mc-io.c +++ b/drivers/bus/fsl-mc/mc-io.c @@ -209,9 +209,19 @@ int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, if (error < 0) goto error_cleanup_resource; + dpmcp_dev->consumer_link = device_link_add(&mc_dev->dev, + &dpmcp_dev->dev, + DL_FLAG_AUTOREMOVE_CONSUMER); + if (!dpmcp_dev->consumer_link) { + error = -EINVAL; + goto error_cleanup_mc_io; + } + *new_mc_io = mc_io; return 0; +error_cleanup_mc_io: + fsl_destroy_mc_io(mc_io); error_cleanup_resource: fsl_mc_resource_free(resource); return error; @@ -244,6 +254,9 @@ void fsl_mc_portal_free(struct fsl_mc_io *mc_io) fsl_destroy_mc_io(mc_io); fsl_mc_resource_free(resource); + + device_link_del(dpmcp_dev->consumer_link); + dpmcp_dev->consumer_link = NULL; } EXPORT_SYMBOL_GPL(fsl_mc_portal_free); -- cgit v1.2.3 From 3c0d64e867ed78a782a8a00d3b519396d9c5a2db Mon Sep 17 00:00:00 2001 From: Li Yang Date: Fri, 11 Jan 2019 15:55:57 -0600 Subject: soc: fsl: guts: reuse machine name from device tree Reuse the string machine from the device tree data structure instead of duplicating the data again. This also prevents a potential memory allocation failure that was not handled previously. Also fixes an early put of root device node. Reported-by: Nicholas Mc Guire Signed-off-by: Li Yang --- drivers/soc/fsl/guts.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c index 302e0c8d69d9..4f9655087bd7 100644 --- a/drivers/soc/fsl/guts.c +++ b/drivers/soc/fsl/guts.c @@ -32,6 +32,7 @@ struct fsl_soc_die_attr { static struct guts *guts; static struct soc_device_attribute soc_dev_attr; static struct soc_device *soc_dev; +static struct device_node *root; /* SoC die attribute definition for QorIQ platform */ @@ -132,7 +133,7 @@ EXPORT_SYMBOL(fsl_guts_get_svr); static int fsl_guts_probe(struct platform_device *pdev) { - struct device_node *root, *np = pdev->dev.of_node; + struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct resource *res; const struct fsl_soc_die_attr *soc_die; @@ -155,9 +156,8 @@ static int fsl_guts_probe(struct platform_device *pdev) root = of_find_node_by_path("/"); if (of_property_read_string(root, "model", &machine)) of_property_read_string_index(root, "compatible", 0, &machine); - of_node_put(root); if (machine) - soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL); + soc_dev_attr.machine = machine; svr = fsl_guts_get_svr(); soc_die = fsl_soc_die_match(svr, fsl_soc_die); @@ -192,6 +192,7 @@ static int fsl_guts_probe(struct platform_device *pdev) static int fsl_guts_remove(struct platform_device *dev) { soc_device_unregister(soc_dev); + of_node_put(root); return 0; } -- cgit v1.2.3 From e59e59b80e33b62a4c6f18435907ebd2317e2200 Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Tue, 18 Dec 2018 16:01:29 +0000 Subject: firmware: imx: scu-pd: add fallback compatible string support SCU power domain can be used in the same way by IMX8QXP and IMX8QM SoCs. Make the driver support the fallback compatible string "fsl,scu-pd" to allow other SoCs to reuse the common part. Cc: Ulf Hansson Cc: Rob Herring Cc: Shawn Guo Cc: Sascha Hauer Cc: Fabio Estevam Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Signed-off-by: Dong Aisheng Reviewed-by: Ulf Hansson Signed-off-by: Shawn Guo --- drivers/firmware/imx/scu-pd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index 407245f2efd0..39a94c7177fc 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -322,6 +322,7 @@ static int imx_sc_pd_probe(struct platform_device *pdev) static const struct of_device_id imx_sc_pd_match[] = { { .compatible = "fsl,imx8qxp-scu-pd", &imx8qxp_scu_pd}, + { .compatible = "fsl,scu-pd", &imx8qxp_scu_pd}, { /* sentinel */ } }; -- cgit v1.2.3 From fc9ac87eabb23b4c354cd2f3b89d94a0db9f9fdc Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 27 Nov 2018 22:33:43 -0600 Subject: scsi: qla4xxx: ql4_os: mark expected switch fall-through In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Notice that, in this particular case, I replaced "allow fall-through" with a "fall through" annotation, which is what GCC is expecting to find. Signed-off-by: Gustavo A. R. Silva Acked-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 949e186cc5d7..0a1940f947dc 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -2875,7 +2875,7 @@ static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess, chap_tbl.secret_len); } } - /* allow fall-through */ + /* fall through */ default: return iscsi_session_get_param(cls_sess, param, buf); } -- cgit v1.2.3 From 211d62a8ce689bf8e7fd0ede67b3a6b1d8de970b Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 27 Nov 2018 22:33:54 -0600 Subject: scsi: st: mark expected switch fall-throughs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Addresses-Coverity-ID: 114994 ("Missing break in switch") Addresses-Coverity-ID: 114995 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Acked-by: Kai Mäkisara Signed-off-by: Martin K. Petersen --- drivers/scsi/st.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 7ff22d3f03e3..7c7a742a5ef7 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -337,12 +337,14 @@ static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s) switch (sense[0] & 0x7f) { case 0x71: s->deferred = 1; + /* fall through */ case 0x70: s->fixed_format = 1; s->flags = sense[2] & 0xe0; break; case 0x73: s->deferred = 1; + /* fall through */ case 0x72: s->fixed_format = 0; ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4); @@ -2721,6 +2723,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon switch (cmd_in) { case MTFSFM: chg_eof = 0; /* Changed from the FSF after this */ + /* fall through */ case MTFSF: cmd[0] = SPACE; cmd[1] = 0x01; /* Space FileMarks */ @@ -2735,6 +2738,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon break; case MTBSFM: chg_eof = 0; /* Changed from the FSF after this */ + /* fall through */ case MTBSF: cmd[0] = SPACE; cmd[1] = 0x01; /* Space FileMarks */ -- cgit v1.2.3 From b9f57f5805cf0e72db20a435e72e8b557a8d28b1 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 27 Nov 2018 22:28:57 -0600 Subject: scsi: esas2r: esas2r_init: mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Signed-off-by: Gustavo A. R. Silva Acked-by: Bradley Grove Signed-off-by: Martin K. Petersen --- drivers/scsi/esas2r/esas2r_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index 46b2c83ba21f..950cd92df2ff 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -1241,6 +1241,7 @@ static bool esas2r_format_init_msg(struct esas2r_adapter *a, a->init_msg = ESAS2R_INIT_MSG_GET_INIT; break; } + /* fall through */ case ESAS2R_INIT_MSG_GET_INIT: if (msg == ESAS2R_INIT_MSG_GET_INIT) { @@ -1254,7 +1255,7 @@ static bool esas2r_format_init_msg(struct esas2r_adapter *a, esas2r_hdebug("FAILED"); } } - /* fall through */ + /* fall through */ default: rq->req_stat = RS_SUCCESS; -- cgit v1.2.3 From 8425811b8d95d441499d963b7d09b7910c630f71 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 27 Nov 2018 22:27:15 -0600 Subject: scsi: bfa: bfa_fcs_lport: Mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Notice that, in this particular case, I replaced "!!! fall through !!!" with a "fall through" annotation, which is what GCC is expecting to find. Signed-off-by: Gustavo A. R. Silva Acked-by: Sudarsana Kalluru Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_fcs_lport.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index b4f2c1d8742e..646f09f66443 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -6430,9 +6430,7 @@ bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport, switch (event) { case BFA_FCS_VPORT_SM_OFFLINE: bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - /* - * !!! fall through !!! - */ + /* fall through */ case BFA_FCS_VPORT_SM_RSP_OK: case BFA_FCS_VPORT_SM_RSP_ERROR: @@ -6458,9 +6456,7 @@ bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, switch (event) { case BFA_FCS_VPORT_SM_OFFLINE: bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - /* - * !!! fall through !!! - */ + /* fall through */ case BFA_FCS_VPORT_SM_RSP_OK: case BFA_FCS_VPORT_SM_RSP_ERROR: -- cgit v1.2.3 From d14e4cd45ac83edf96b249a222b02344889fb6f9 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 27 Nov 2018 22:27:23 -0600 Subject: scsi: bfa: bfa_fcs_rport: Mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Notice that I replaced "!! fall through !!" and "!!! fall through !!!" comments with "fall through" annotations, which is what GCC is expecting to find. Addresses-Coverity-ID: 744899 ("Missing break in switch") Addresses-Coverity-ID: 744900 ("Missing break in switch") Addresses-Coverity-ID: 744901 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Acked-by: Sudarsana Kalluru Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_fcs_rport.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c index de50349a39ce..1e400f2aaece 100644 --- a/drivers/scsi/bfa/bfa_fcs_rport.c +++ b/drivers/scsi/bfa/bfa_fcs_rport.c @@ -427,17 +427,13 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) case RPSM_EVENT_LOGO_RCVD: bfa_fcs_rport_send_logo_acc(rport); - /* - * !! fall through !! - */ + /* fall through */ case RPSM_EVENT_PRLO_RCVD: if (rport->prlo == BFA_TRUE) bfa_fcs_rport_send_prlo_acc(rport); bfa_fcxp_discard(rport->fcxp); - /* - * !! fall through !! - */ + /* fall through */ case RPSM_EVENT_FAILED: if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) { rport->plogi_retries++; @@ -868,9 +864,7 @@ bfa_fcs_rport_sm_adisc_online(struct bfa_fcs_rport_s *rport, * At least go offline when a PLOGI is received. */ bfa_fcxp_discard(rport->fcxp); - /* - * !!! fall through !!! - */ + /* fall through */ case RPSM_EVENT_FAILED: case RPSM_EVENT_ADDRESS_CHANGE: @@ -1056,6 +1050,7 @@ bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_LOGO_RCVD: bfa_fcs_rport_send_logo_acc(rport); + /* fall through */ case RPSM_EVENT_PRLO_RCVD: if (rport->prlo == BFA_TRUE) bfa_fcs_rport_send_prlo_acc(rport); @@ -1144,9 +1139,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_send_plogiacc(rport, NULL); break; } - /* - * !! fall through !! - */ + /* fall through */ case RPSM_EVENT_ADDRESS_CHANGE: if (!bfa_fcs_lport_is_online(rport->port)) { @@ -1303,6 +1296,7 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_LOGO_RCVD: bfa_fcs_rport_send_logo_acc(rport); + /* fall through */ case RPSM_EVENT_PRLO_RCVD: if (rport->prlo == BFA_TRUE) bfa_fcs_rport_send_prlo_acc(rport); @@ -1346,6 +1340,7 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_LOGO_RCVD: bfa_fcs_rport_send_logo_acc(rport); + /* fall through */ case RPSM_EVENT_PRLO_RCVD: if (rport->prlo == BFA_TRUE) bfa_fcs_rport_send_prlo_acc(rport); -- cgit v1.2.3 From f1b1dceedd7b046d04031a187aa1d51a62d8847c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 27 Nov 2018 22:27:32 -0600 Subject: scsi: bfa: bfa_ioc: Mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Notice that, in this particular case, I replaced "!!! fall through !!!" comment with "fall through" annotations, which is what GCC is expecting to find. Addresses-Coverity-ID: 146155 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Acked-by: Sudarsana Kalluru Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_ioc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 9631877aba4f..79a55c3615be 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -978,9 +978,7 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) case IOCPF_E_INITFAIL: bfa_iocpf_timer_stop(ioc); - /* - * !!! fall through !!! - */ + /* fall through */ case IOCPF_E_TIMEOUT: writel(1, ioc->ioc_regs.ioc_sem_reg); @@ -1056,9 +1054,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) case IOCPF_E_FAIL: bfa_iocpf_timer_stop(ioc); - /* - * !!! fall through !!! - */ + /* fall through */ case IOCPF_E_TIMEOUT: bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL); @@ -6007,6 +6003,7 @@ bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf, case BFA_DCONF_SM_IOCDISABLE: case BFA_DCONF_SM_FLASH_COMP: bfa_timer_stop(&dconf->timer); + /* fall through */ case BFA_DCONF_SM_TIMEOUT: bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE); -- cgit v1.2.3 From 4edff70494e4c7c4371270a7b0b56b2776adc0ee Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 27 Nov 2018 22:26:19 -0600 Subject: scsi: aic7xxx: aic79xx: mark expected switch fall-through In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Notice that, in some cases, I replaced "FALLTHROUGH" with a "fall through" annotation and then placed it at the bottom of the corresponding switch case, which is what GCC is expecting to find. Addresses-Coverity-ID: 114961 ("Missing break in switch") Addresses-Coverity-ID: 114962 ("Missing break in switch") Addresses-Coverity-ID: 114963 ("Missing break in switch") Addresses-Coverity-ID: 114964 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic79xx_core.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 9ee75c9a9aa1..7e5044bf05c0 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -2285,6 +2285,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) switch (scb->hscb->task_management) { case SIU_TASKMGMT_ABORT_TASK: tag = SCB_GET_TAG(scb); + /* fall through */ case SIU_TASKMGMT_ABORT_TASK_SET: case SIU_TASKMGMT_CLEAR_TASK_SET: lun = scb->hscb->lun; @@ -2295,6 +2296,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) break; case SIU_TASKMGMT_LUN_RESET: lun = scb->hscb->lun; + /* fall through */ case SIU_TASKMGMT_TARGET_RESET: { struct ahd_devinfo devinfo; @@ -6550,8 +6552,8 @@ ahd_fini_scbdata(struct ahd_softc *ahd) kfree(sns_map); } ahd_dma_tag_destroy(ahd, scb_data->sense_dmat); - /* FALLTHROUGH */ } + /* fall through */ case 6: { struct map_node *sg_map; @@ -6565,8 +6567,8 @@ ahd_fini_scbdata(struct ahd_softc *ahd) kfree(sg_map); } ahd_dma_tag_destroy(ahd, scb_data->sg_dmat); - /* FALLTHROUGH */ } + /* fall through */ case 5: { struct map_node *hscb_map; @@ -7209,6 +7211,7 @@ ahd_init(struct ahd_softc *ahd) case FLX_CSTAT_OVER: case FLX_CSTAT_UNDER: warn_user++; + /* fall through */ case FLX_CSTAT_INVALID: case FLX_CSTAT_OKAY: if (warn_user == 0 && bootverbose == 0) @@ -8413,7 +8416,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, if ((scb->flags & SCB_ACTIVE) == 0) printk("Inactive SCB in Waiting List\n"); ahd_done_with_status(ahd, scb, status); - /* FALLTHROUGH */ + /* fall through */ case SEARCH_REMOVE: ahd_rem_wscb(ahd, scbid, prev, next, tid); *list_tail = prev; @@ -8422,6 +8425,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, break; case SEARCH_PRINT: printk("0x%x ", scbid); + /* fall through */ case SEARCH_COUNT: prev = scbid; break; @@ -9547,8 +9551,8 @@ ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts) { fmt3_ins = &instr.format3; fmt3_ins->address = ahd_resolve_seqaddr(ahd, fmt3_ins->address); - /* FALLTHROUGH */ } + /* fall through */ case AIC_OP_OR: case AIC_OP_AND: case AIC_OP_XOR: @@ -9559,7 +9563,7 @@ ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts) fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; } fmt1_ins->parity = 0; - /* FALLTHROUGH */ + /* fall through */ case AIC_OP_ROL: { int i, count; -- cgit v1.2.3 From 7855d2ba1172d716d96a628af7c5bafa5725ac57 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 21 Dec 2018 09:33:44 -0800 Subject: scsi: qla2xxx: Add protection mask module parameters Allow user to selectively enable/disable DIF/DIX protection capabilities mask. Signed-off-by: Martin K. Petersen Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ea69dafc9774..3a4f68f40057 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -285,6 +285,20 @@ MODULE_PARM_DESC(qla2xuseresexchforels, "Reserve 1/2 of emergency exchanges for ELS.\n" " 0 (default): disabled"); +int ql2xprotmask; +module_param(ql2xprotmask, int, 0644); +MODULE_PARM_DESC(ql2xprotmask, + "Override DIF/DIX protection capabilities mask\n" + "Default is 0 which sets protection mask based on " + "capabilities reported by HBA firmware.\n"); + +int ql2xprotguard; +module_param(ql2xprotguard, int, 0644); +MODULE_PARM_DESC(ql2xprotguard, "Override choice of DIX checksum\n" + " 0 -- Let HBA firmware decide\n" + " 1 -- Force T10 CRC\n" + " 2 -- Force IP checksum\n"); + /* * SCSI host template entry points */ @@ -3342,13 +3356,16 @@ skip_dpc: "Registering for DIF/DIX type 1 and 3 protection.\n"); if (ql2xenabledif == 1) prot = SHOST_DIX_TYPE0_PROTECTION; - scsi_host_set_prot(host, - prot | SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE2_PROTECTION - | SHOST_DIF_TYPE3_PROTECTION - | SHOST_DIX_TYPE1_PROTECTION - | SHOST_DIX_TYPE2_PROTECTION - | SHOST_DIX_TYPE3_PROTECTION); + if (ql2xprotmask) + scsi_host_set_prot(host, ql2xprotmask); + else + scsi_host_set_prot(host, + prot | SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE2_PROTECTION + | SHOST_DIF_TYPE3_PROTECTION + | SHOST_DIX_TYPE1_PROTECTION + | SHOST_DIX_TYPE2_PROTECTION + | SHOST_DIX_TYPE3_PROTECTION); guard = SHOST_DIX_GUARD_CRC; @@ -3356,7 +3373,10 @@ skip_dpc: (ql2xenabledif > 1 || IS_PI_DIFB_DIX0_CAPABLE(ha))) guard |= SHOST_DIX_GUARD_IP; - scsi_host_set_guard(host, guard); + if (ql2xprotguard) + scsi_host_set_guard(host, ql2xprotguard); + else + scsi_host_set_guard(host, guard); } else base_vha->flags.difdix_supported = 0; } -- cgit v1.2.3 From 50b812755e9766fa0a1a28533f4d11a34a5b813e Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 21 Dec 2018 09:33:45 -0800 Subject: scsi: qla2xxx: Fix DMA error when the DIF sg buffer crosses 4GB boundary When SGE buffer containing DIF information crosses 4G boundary, it results in DMA error. This patch fixes this issue by calculating SGE buffer size and if it crosses 4G boundary, driver will split it into multiple SGE buffers to avoid DMA error. Signed-off-by: Giridhar Malavali Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 21 ++- drivers/scsi/qla2xxx/qla_def.h | 28 ++++ drivers/scsi/qla2xxx/qla_gbl.h | 3 +- drivers/scsi/qla2xxx/qla_iocb.c | 335 +++++++++++++++++++++++++++++++------- drivers/scsi/qla2xxx/qla_isr.c | 11 ++ drivers/scsi/qla2xxx/qla_os.c | 169 ++++++++++++++++++- drivers/scsi/qla2xxx/qla_target.c | 2 +- drivers/scsi/qla2xxx/qla_target.h | 2 + 8 files changed, 503 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 00444dc79756..8b4dd72011bf 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1002,7 +1002,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon) /* Scsi_Host attributes. */ static ssize_t -qla2x00_drvr_version_show(struct device *dev, +qla2x00_driver_version_show(struct device *dev, struct device_attribute *attr, char *buf) { return scnprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str); @@ -2059,7 +2059,21 @@ ql2xiniexchg_store(struct device *dev, struct device_attribute *attr, return strlen(buf); } -static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); +static ssize_t +qla2x00_dif_bundle_statistics_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + return scnprintf(buf, PAGE_SIZE, + "cross=%llu read=%llu write=%llu kalloc=%llu dma_alloc=%llu unusable=%u\n", + ha->dif_bundle_crossed_pages, ha->dif_bundle_reads, + ha->dif_bundle_writes, ha->dif_bundle_kallocs, + ha->dif_bundle_dma_allocs, ha->pool.unusable.count); +} + +static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_driver_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); static DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL); @@ -2112,6 +2126,8 @@ static DEVICE_ATTR(zio_threshold, 0644, static DEVICE_ATTR_RW(qlini_mode); static DEVICE_ATTR_RW(ql2xexchoffld); static DEVICE_ATTR_RW(ql2xiniexchg); +static DEVICE_ATTR(dif_bundle_statistics, 0444, + qla2x00_dif_bundle_statistics_show, NULL); struct device_attribute *qla2x00_host_attrs[] = { @@ -2150,6 +2166,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_min_link_speed, &dev_attr_max_speed_sup, &dev_attr_zio_threshold, + &dev_attr_dif_bundle_statistics, NULL, /* reserve for qlini_mode */ NULL, /* reserve for ql2xiniexchg */ NULL, /* reserve for ql2xexchoffld */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 26b93c563f92..97f66b142ff2 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -314,6 +314,7 @@ struct srb_cmd { #define SRB_CRC_PROT_DMA_VALID BIT_4 /* DIF: prot DMA valid */ #define SRB_CRC_CTX_DSD_VALID BIT_5 /* DIF: dsd_list valid */ #define SRB_WAKEUP_ON_COMP BIT_6 +#define SRB_DIF_BUNDL_DMA_VALID BIT_7 /* DIF: DMA list valid */ /* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */ #define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID) @@ -1892,6 +1893,13 @@ struct crc_context { /* List of DMA context transfers */ struct list_head dsd_list; + /* List of DIF Bundling context DMA address */ + struct list_head ldif_dsd_list; + u8 no_ldif_dsd; + + struct list_head ldif_dma_hndl_list; + u32 dif_bundl_len; + u8 no_dif_bundl; /* This structure should not exceed 512 bytes */ }; @@ -4184,6 +4192,26 @@ struct qla_hw_data { uint16_t min_link_speed; uint16_t max_speed_sup; + /* DMA pool for the DIF bundling buffers */ + struct dma_pool *dif_bundl_pool; + #define DIF_BUNDLING_DMA_POOL_SIZE 1024 + struct { + struct { + struct list_head head; + uint count; + } good; + struct { + struct list_head head; + uint count; + } unusable; + } pool; + + unsigned long long dif_bundle_crossed_pages; + unsigned long long dif_bundle_reads; + unsigned long long dif_bundle_writes; + unsigned long long dif_bundle_kallocs; + unsigned long long dif_bundle_dma_allocs; + atomic_t nvme_active_aen_cnt; uint16_t nvme_last_rptd_aen; /* Last recorded aen count */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 3673fcdb033a..bcc17a7261e7 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -160,6 +160,7 @@ extern int ql2xautodetectsfp; extern int ql2xenablemsix; extern int qla2xuseresexchforels; extern int ql2xexlogins; +extern int ql2xdifbundlinginternalbuffers; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -285,7 +286,7 @@ extern int qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *, srb_t *, extern int qla24xx_walk_and_build_sglist(struct qla_hw_data *, srb_t *, uint32_t *, uint16_t, struct qla_tc_param *); extern int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *, srb_t *, - uint32_t *, uint16_t, struct qla_tc_param *); + uint32_t *, uint16_t, struct qla_tgt_cmd *); extern int qla24xx_get_one_block_sg(uint32_t, struct qla2_sgx *, uint32_t *); extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *); extern int qla24xx_build_scsi_crc_2_iocbs(srb_t *, diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 032635321ad6..65ba0e36ee60 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1098,88 +1098,300 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, - uint32_t *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) + uint32_t *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc) { - void *next_dsd; - uint8_t avail_dsds = 0; - uint32_t dsd_list_len; - struct dsd_dma *dsd_ptr; + struct dsd_dma *dsd_ptr = NULL, *dif_dsd, *nxt_dsd; struct scatterlist *sg, *sgl; - int i; - struct scsi_cmnd *cmd; - uint32_t *cur_dsd = dsd; - uint16_t used_dsds = tot_dsds; + struct crc_context *difctx = NULL; struct scsi_qla_host *vha; + uint dsd_list_len; + uint avail_dsds = 0; + uint used_dsds = tot_dsds; + bool dif_local_dma_alloc = false; + bool direction_to_device = false; + int i; if (sp) { - cmd = GET_CMD_SP(sp); + struct scsi_cmnd *cmd = GET_CMD_SP(sp); sgl = scsi_prot_sglist(cmd); vha = sp->vha; + difctx = sp->u.scmd.ctx; + direction_to_device = cmd->sc_data_direction == DMA_TO_DEVICE; + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, + "%s: scsi_cmnd: %p, crc_ctx: %p, sp: %p\n", + __func__, cmd, difctx, sp); } else if (tc) { vha = tc->vha; sgl = tc->prot_sg; + difctx = tc->ctx; + direction_to_device = tc->dma_data_direction == DMA_TO_DEVICE; } else { BUG(); return 1; } - ql_dbg(ql_dbg_tgt, vha, 0xe021, - "%s: enter\n", __func__); - - for_each_sg(sgl, sg, tot_dsds, i) { - dma_addr_t sle_dma; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? - QLA_DSDS_PER_IOCB : used_dsds; - dsd_list_len = (avail_dsds + 1) * 12; - used_dsds -= avail_dsds; - - /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); - if (!dsd_ptr) - return 1; - - /* allocate new list */ - dsd_ptr->dsd_addr = next_dsd = - dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, - &dsd_ptr->dsd_list_dma); - - if (!next_dsd) { - /* - * Need to cleanup only this dsd_ptr, rest - * will be done by sp_free_dma() - */ - kfree(dsd_ptr); - return 1; + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, + "%s: enter (write=%u)\n", __func__, direction_to_device); + + /* if initiator doing write or target doing read */ + if (direction_to_device) { + for_each_sg(sgl, sg, tot_dsds, i) { + dma_addr_t sle_phys = sg_phys(sg); + + /* If SGE addr + len flips bits in upper 32-bits */ + if (MSD(sle_phys + sg->length) ^ MSD(sle_phys)) { + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe022, + "%s: page boundary crossing (phys=%llx len=%x)\n", + __func__, sle_phys, sg->length); + + if (difctx) { + ha->dif_bundle_crossed_pages++; + dif_local_dma_alloc = true; + } else { + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, + vha, 0xe022, + "%s: difctx pointer is NULL\n", + __func__); + } + break; + } + } + ha->dif_bundle_writes++; + } else { + ha->dif_bundle_reads++; + } + + if (ql2xdifbundlinginternalbuffers) + dif_local_dma_alloc = direction_to_device; + + if (dif_local_dma_alloc) { + u32 track_difbundl_buf = 0; + u32 ldma_sg_len = 0; + u8 ldma_needed = 1; + + difctx->no_dif_bundl = 0; + difctx->dif_bundl_len = 0; + + /* Track DSD buffers */ + INIT_LIST_HEAD(&difctx->ldif_dsd_list); + /* Track local DMA buffers */ + INIT_LIST_HEAD(&difctx->ldif_dma_hndl_list); + + for_each_sg(sgl, sg, tot_dsds, i) { + u32 sglen = sg_dma_len(sg); + + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe023, + "%s: sg[%x] (phys=%llx sglen=%x) ldma_sg_len: %x dif_bundl_len: %x ldma_needed: %x\n", + __func__, i, sg_phys(sg), sglen, ldma_sg_len, + difctx->dif_bundl_len, ldma_needed); + + while (sglen) { + u32 xfrlen = 0; + + if (ldma_needed) { + /* + * Allocate list item to store + * the DMA buffers + */ + dsd_ptr = kzalloc(sizeof(*dsd_ptr), + GFP_ATOMIC); + if (!dsd_ptr) { + ql_dbg(ql_dbg_tgt, vha, 0xe024, + "%s: failed alloc dsd_ptr\n", + __func__); + return 1; + } + ha->dif_bundle_kallocs++; + + /* allocate dma buffer */ + dsd_ptr->dsd_addr = dma_pool_alloc + (ha->dif_bundl_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + if (!dsd_ptr->dsd_addr) { + ql_dbg(ql_dbg_tgt, vha, 0xe024, + "%s: failed alloc ->dsd_ptr\n", + __func__); + /* + * need to cleanup only this + * dsd_ptr rest will be done + * by sp_free_dma() + */ + kfree(dsd_ptr); + ha->dif_bundle_kallocs--; + return 1; + } + ha->dif_bundle_dma_allocs++; + ldma_needed = 0; + difctx->no_dif_bundl++; + list_add_tail(&dsd_ptr->list, + &difctx->ldif_dma_hndl_list); + } + + /* xfrlen is min of dma pool size and sglen */ + xfrlen = (sglen > + (DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len)) ? + DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len : + sglen; + + /* replace with local allocated dma buffer */ + sg_pcopy_to_buffer(sgl, sg_nents(sgl), + dsd_ptr->dsd_addr + ldma_sg_len, xfrlen, + difctx->dif_bundl_len); + difctx->dif_bundl_len += xfrlen; + sglen -= xfrlen; + ldma_sg_len += xfrlen; + if (ldma_sg_len == DIF_BUNDLING_DMA_POOL_SIZE || + sg_is_last(sg)) { + ldma_needed = 1; + ldma_sg_len = 0; + } } + } - if (sp) { - list_add_tail(&dsd_ptr->list, - &((struct crc_context *) - sp->u.scmd.ctx)->dsd_list); + track_difbundl_buf = used_dsds = difctx->no_dif_bundl; + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe025, + "dif_bundl_len=%x, no_dif_bundl=%x track_difbundl_buf: %x\n", + difctx->dif_bundl_len, difctx->no_dif_bundl, + track_difbundl_buf); - sp->flags |= SRB_CRC_CTX_DSD_VALID; - } else { - list_add_tail(&dsd_ptr->list, - &(tc->ctx->dsd_list)); - *tc->ctx_dsd_alloced = 1; + if (sp) + sp->flags |= SRB_DIF_BUNDL_DMA_VALID; + else + tc->prot_flags = DIF_BUNDL_DMA_VALID; + + list_for_each_entry_safe(dif_dsd, nxt_dsd, + &difctx->ldif_dma_hndl_list, list) { + u32 sglen = (difctx->dif_bundl_len > + DIF_BUNDLING_DMA_POOL_SIZE) ? + DIF_BUNDLING_DMA_POOL_SIZE : difctx->dif_bundl_len; + + BUG_ON(track_difbundl_buf == 0); + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, + 0xe024, + "%s: adding continuation iocb's\n", + __func__); + avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? + QLA_DSDS_PER_IOCB : used_dsds; + dsd_list_len = (avail_dsds + 1) * 12; + used_dsds -= avail_dsds; + + /* allocate tracking DS */ + dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); + if (!dsd_ptr) { + ql_dbg(ql_dbg_tgt, vha, 0xe026, + "%s: failed alloc dsd_ptr\n", + __func__); + return 1; + } + ha->dif_bundle_kallocs++; + + difctx->no_ldif_dsd++; + /* allocate new list */ + dsd_ptr->dsd_addr = + dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + if (!dsd_ptr->dsd_addr) { + ql_dbg(ql_dbg_tgt, vha, 0xe026, + "%s: failed alloc ->dsd_addr\n", + __func__); + /* + * need to cleanup only this dsd_ptr + * rest will be done by sp_free_dma() + */ + kfree(dsd_ptr); + ha->dif_bundle_kallocs--; + return 1; + } + ha->dif_bundle_dma_allocs++; + + if (sp) { + list_add_tail(&dsd_ptr->list, + &difctx->ldif_dsd_list); + sp->flags |= SRB_CRC_CTX_DSD_VALID; + } else { + list_add_tail(&dsd_ptr->list, + &difctx->ldif_dsd_list); + tc->ctx_dsd_alloced = 1; + } + + /* add new list to cmd iocb or last list */ + *cur_dsd++ = + cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = + cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = dsd_list_len; + cur_dsd = dsd_ptr->dsd_addr; } - - /* add new list to cmd iocb or last list */ - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; - cur_dsd = (uint32_t *)next_dsd; + *cur_dsd++ = cpu_to_le32(LSD(dif_dsd->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(MSD(dif_dsd->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(sglen); + avail_dsds--; + difctx->dif_bundl_len -= sglen; + track_difbundl_buf--; } - sle_dma = sg_dma_address(sg); - - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - avail_dsds--; + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe026, + "%s: no_ldif_dsd:%x, no_dif_bundl:%x\n", __func__, + difctx->no_ldif_dsd, difctx->no_dif_bundl); + } else { + for_each_sg(sgl, sg, tot_dsds, i) { + dma_addr_t sle_dma; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? + QLA_DSDS_PER_IOCB : used_dsds; + dsd_list_len = (avail_dsds + 1) * 12; + used_dsds -= avail_dsds; + + /* allocate tracking DS */ + dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); + if (!dsd_ptr) { + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, + vha, 0xe027, + "%s: failed alloc dsd_dma...\n", + __func__); + return 1; + } + + /* allocate new list */ + dsd_ptr->dsd_addr = + dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + if (!dsd_ptr->dsd_addr) { + /* need to cleanup only this dsd_ptr */ + /* rest will be done by sp_free_dma() */ + kfree(dsd_ptr); + return 1; + } + + if (sp) { + list_add_tail(&dsd_ptr->list, + &difctx->dsd_list); + sp->flags |= SRB_CRC_CTX_DSD_VALID; + } else { + list_add_tail(&dsd_ptr->list, + &difctx->dsd_list); + tc->ctx_dsd_alloced = 1; + } + + /* add new list to cmd iocb or last list */ + *cur_dsd++ = + cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = + cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = dsd_list_len; + cur_dsd = dsd_ptr->dsd_addr; + } + sle_dma = sg_dma_address(sg); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + avail_dsds--; + } } /* Null termination */ *cur_dsd++ = 0; @@ -1187,7 +1399,6 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, *cur_dsd++ = 0; return 0; } - /** * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command * Type 6 IOCB types. diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 30d3090842f8..5c1de6ed825b 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2725,6 +2725,17 @@ check_scsi_status: cp->device->vendor); break; + case CS_DMA: + ql_log(ql_log_info, fcport->vha, 0x3022, + "CS_DMA error: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu portid=%06x oxid=0x%x cdb=%10phN len=0x%x rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n", + comp_status, scsi_status, res, vha->host_no, + cp->device->id, cp->device->lun, fcport->d_id.b24, + ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len, + resid_len, fw_resid_len, sp, cp); + ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee, + pkt, sizeof(*sts24)); + res = DID_ERROR << 16; + break; default: res = DID_ERROR << 16; break; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3a4f68f40057..715b5526fb0a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -299,6 +299,13 @@ MODULE_PARM_DESC(ql2xprotguard, "Override choice of DIX checksum\n" " 1 -- Force T10 CRC\n" " 2 -- Force IP checksum\n"); +int ql2xdifbundlinginternalbuffers; +module_param(ql2xdifbundlinginternalbuffers, int, 0644); +MODULE_PARM_DESC(ql2xdifbundlinginternalbuffers, + "Force using internal buffers for DIF information\n" + "0 (Default). Based on check.\n" + "1 Force using internal buffers\n"); + /* * SCSI host template entry points */ @@ -818,7 +825,44 @@ qla2xxx_qpair_sp_free_dma(void *ptr) ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; ha->gbl_dsd_avail += ctx1->dsd_use_cnt; mempool_free(ctx1, ha->ctx_mempool); + sp->flags &= ~SRB_FCP_CMND_DMA_VALID; + } + if (sp->flags & SRB_DIF_BUNDL_DMA_VALID) { + struct crc_context *difctx = sp->u.scmd.ctx; + struct dsd_dma *dif_dsd, *nxt_dsd; + + list_for_each_entry_safe(dif_dsd, nxt_dsd, + &difctx->ldif_dma_hndl_list, list) { + list_del(&dif_dsd->list); + dma_pool_free(ha->dif_bundl_pool, dif_dsd->dsd_addr, + dif_dsd->dsd_list_dma); + kfree(dif_dsd); + difctx->no_dif_bundl--; + } + + list_for_each_entry_safe(dif_dsd, nxt_dsd, + &difctx->ldif_dsd_list, list) { + list_del(&dif_dsd->list); + dma_pool_free(ha->dl_dma_pool, dif_dsd->dsd_addr, + dif_dsd->dsd_list_dma); + kfree(dif_dsd); + difctx->no_ldif_dsd--; + } + + if (difctx->no_ldif_dsd) { + ql_dbg(ql_dbg_tgt+ql_dbg_verbose, sp->vha, 0xe022, + "%s: difctx->no_ldif_dsd=%x\n", + __func__, difctx->no_ldif_dsd); + } + + if (difctx->no_dif_bundl) { + ql_dbg(ql_dbg_tgt+ql_dbg_verbose, sp->vha, 0xe022, + "%s: difctx->no_dif_bundl=%x\n", + __func__, difctx->no_dif_bundl); + } + sp->flags &= ~SRB_DIF_BUNDL_DMA_VALID; } + end: CMD_SP(cmd) = NULL; qla2xxx_rel_qpair_sp(sp->qpair, sp); @@ -4017,9 +4061,86 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, "Failed to allocate memory for fcp_cmnd_dma_pool.\n"); goto fail_dl_dma_pool; } + + if (ql2xenabledif) { + u64 bufsize = DIF_BUNDLING_DMA_POOL_SIZE; + struct dsd_dma *dsd, *nxt; + uint i; + /* Creata a DMA pool of buffers for DIF bundling */ + ha->dif_bundl_pool = dma_pool_create(name, + &ha->pdev->dev, DIF_BUNDLING_DMA_POOL_SIZE, 8, 0); + if (!ha->dif_bundl_pool) { + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0024, + "%s: failed create dif_bundl_pool\n", + __func__); + goto fail_dif_bundl_dma_pool; + } + + INIT_LIST_HEAD(&ha->pool.good.head); + INIT_LIST_HEAD(&ha->pool.unusable.head); + ha->pool.good.count = 0; + ha->pool.unusable.count = 0; + for (i = 0; i < 128; i++) { + dsd = kzalloc(sizeof(*dsd), GFP_ATOMIC); + if (!dsd) { + ql_dbg_pci(ql_dbg_init, ha->pdev, + 0xe0ee, "%s: failed alloc dsd\n", + __func__); + return 1; + } + ha->dif_bundle_kallocs++; + + dsd->dsd_addr = dma_pool_alloc( + ha->dif_bundl_pool, GFP_ATOMIC, + &dsd->dsd_list_dma); + if (!dsd->dsd_addr) { + ql_dbg_pci(ql_dbg_init, ha->pdev, + 0xe0ee, + "%s: failed alloc ->dsd_addr\n", + __func__); + kfree(dsd); + ha->dif_bundle_kallocs--; + continue; + } + ha->dif_bundle_dma_allocs++; + + /* + * if DMA buffer crosses 4G boundary, + * put it on bad list + */ + if (MSD(dsd->dsd_list_dma) ^ + MSD(dsd->dsd_list_dma + bufsize)) { + list_add_tail(&dsd->list, + &ha->pool.unusable.head); + ha->pool.unusable.count++; + } else { + list_add_tail(&dsd->list, + &ha->pool.good.head); + ha->pool.good.count++; + } + } + + /* return the good ones back to the pool */ + list_for_each_entry_safe(dsd, nxt, + &ha->pool.good.head, list) { + list_del(&dsd->list); + dma_pool_free(ha->dif_bundl_pool, + dsd->dsd_addr, dsd->dsd_list_dma); + ha->dif_bundle_dma_allocs--; + kfree(dsd); + ha->dif_bundle_kallocs--; + } + + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0024, + "%s: dif dma pool (good=%u unusable=%u)\n", + __func__, ha->pool.good.count, + ha->pool.unusable.count); + } + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0025, - "dl_dma_pool=%p fcp_cmnd_dma_pool=%p.\n", - ha->dl_dma_pool, ha->fcp_cmnd_dma_pool); + "dl_dma_pool=%p fcp_cmnd_dma_pool=%p dif_bundl_pool=%p.\n", + ha->dl_dma_pool, ha->fcp_cmnd_dma_pool, + ha->dif_bundl_pool); } /* Allocate memory for SNS commands */ @@ -4184,6 +4305,24 @@ fail_free_ms_iocb: dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), ha->sns_cmd, ha->sns_cmd_dma); fail_dma_pool: + if (ql2xenabledif) { + struct dsd_dma *dsd, *nxt; + + list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head, + list) { + list_del(&dsd->list); + dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, + dsd->dsd_list_dma); + ha->dif_bundle_dma_allocs--; + kfree(dsd); + ha->dif_bundle_kallocs--; + ha->pool.unusable.count--; + } + dma_pool_destroy(ha->dif_bundl_pool); + ha->dif_bundl_pool = NULL; + } + +fail_dif_bundl_dma_pool: if (IS_QLA82XX(ha) || ql2xenabledif) { dma_pool_destroy(ha->fcp_cmnd_dma_pool); ha->fcp_cmnd_dma_pool = NULL; @@ -4564,6 +4703,32 @@ qla2x00_mem_free(struct qla_hw_data *ha) mempool_destroy(ha->ctx_mempool); + if (ql2xenabledif) { + struct dsd_dma *dsd, *nxt; + + list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head, + list) { + list_del(&dsd->list); + dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, + dsd->dsd_list_dma); + ha->dif_bundle_dma_allocs--; + kfree(dsd); + ha->dif_bundle_kallocs--; + ha->pool.unusable.count--; + } + list_for_each_entry_safe(dsd, nxt, &ha->pool.good.head, list) { + list_del(&dsd->list); + dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, + dsd->dsd_list_dma); + ha->dif_bundle_dma_allocs--; + kfree(dsd); + ha->dif_bundle_kallocs--; + } + } + + if (ha->dif_bundl_pool) + dma_pool_destroy(ha->dif_bundl_pool); + qlt_mem_free(ha); if (ha->init_cb) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 510337eac106..764b6ed74cfc 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3230,7 +3230,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; if (qla24xx_walk_and_build_prot_sglist(ha, NULL, cur_dsd, - prm->prot_seg_cnt, &tc)) + prm->prot_seg_cnt, cmd)) goto crc_queuing_error; } return QLA_SUCCESS; diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 577e1786a3f1..f3de75000a08 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -928,6 +928,8 @@ struct qla_tgt_cmd { uint64_t lba; uint16_t a_guard, e_guard, a_app_tag, e_app_tag; uint32_t a_ref_tag, e_ref_tag; +#define DIF_BUNDL_DMA_VALID 1 + uint16_t prot_flags; uint64_t jiffies_at_alloc; uint64_t jiffies_at_free; -- cgit v1.2.3 From 01929a65dfa13e18d89264ab1378854a91857e59 Mon Sep 17 00:00:00 2001 From: John Garry Date: Sat, 5 Jan 2019 00:01:27 +0800 Subject: scsi: libsas: Check SMP PHY control function result Currently the SMP PHY control execution result is checked, however the function result for the command is not. As such, we may be missing all potential errors, like SMP FUNCTION FAILED, INVALID REQUEST FRAME LENGTH, etc., meaning the PHY control request has failed. In some scenarios we need to ensure the function result is accepted, so add a check for this. Tested-by: Jian Luo Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 17eb4185f29d..8817b8e6e507 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -614,7 +614,14 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id, } res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE); - + if (res) { + pr_err("ex %016llx phy%02d PHY control failed: %d\n", + SAS_ADDR(dev->sas_addr), phy_id, res); + } else if (pc_resp[2] != SMP_RESP_FUNC_ACC) { + pr_err("ex %016llx phy%02d PHY control failed: function result 0x%x\n", + SAS_ADDR(dev->sas_addr), phy_id, pc_resp[2]); + res = pc_resp[2]; + } kfree(pc_resp); kfree(pc_req); return res; -- cgit v1.2.3 From cec9771d2e954650095aa37a6a97722c8194e7d2 Mon Sep 17 00:00:00 2001 From: John Garry Date: Sat, 5 Jan 2019 00:01:28 +0800 Subject: scsi: libsas: Support SATA PHY connection rate unmatch fixing during discovery +----------+ +----------+ | | | | | |--- 3.0 G ---| |--- 6.0 G --- SAS disk | | | | | |--- 3.0 G ---| |--- 6.0 G --- SAS disk |initiator | | | | device |--- 3.0 G ---| Expander |--- 6.0 G --- SAS disk | | | | | |--- 3.0 G ---| |--- 6.0 G --- SATA disk -->failed to connect | | | | | | | |--- 6.0 G --- SATA disk -->failed to connect | | | | +----------+ +----------+ According to Serial Attached SCSI - 1.1 (SAS-1.1): If an expander PHY attached to a SATA PHY is using a physical link rate greater than the maximum connection rate supported by the pathway from an STP initiator port, a management application client should use the SMP PHY CONTROL function (see 10.4.3.10) to set the PROGRAMMED MAXIMUM PHYSICAL LINK RATE field of the expander PHY to the maximum connection rate supported by the pathway from that STP initiator port. Currently libsas does not support checking if this condition occurs, nor rectifying when it does. Such a condition is not at all common, however it has been seen on some pre-silicon environments where the initiator PHY only supports a 1.5 Gbit maximum linkrate, mated with 12G expander PHYs and 3/6G SATA phy. This patch adds support for checking and rectifying this condition during initial device discovery only. We do support checking min pathway connection rate during revalidation phase, when new devices can be detected in the topology. However we do not support in the case of the the user reprogramming PHY linkrates, such that min pathway condition is not met/maintained. A note on root port PHY rates: The libsas root port PHY rates calculation is broken. Libsas sets the rates (min, max, and current linkrate) of a root port to the same linkrate of the first PHY member of that same port. In doing so, it assumes that all other PHYs which subsequently join the port to have the same negotiated linkrate, when they could actually be different. In practice this doesn't happen, as initiator and expander PHYs are normally initialised with consistent min/max linkrates. This has not caused an issue so far, so leave alone for now. Tested-by: Jian Luo Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 8817b8e6e507..83e3715d30e4 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -824,6 +824,26 @@ static struct domain_device *sas_ex_discover_end_dev( #ifdef CONFIG_SCSI_SAS_ATA if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { + if (child->linkrate > parent->min_linkrate) { + struct sas_phy_linkrates rates = { + .maximum_linkrate = parent->min_linkrate, + .minimum_linkrate = parent->min_linkrate, + }; + int ret; + + pr_notice("ex %016llx phy%02d SATA device linkrate > min pathway connection rate, attempting to lower device linkrate\n", + SAS_ADDR(child->sas_addr), phy_id); + ret = sas_smp_phy_control(parent, phy_id, + PHY_FUNC_LINK_RESET, &rates); + if (ret) { + pr_err("ex %016llx phy%02d SATA device could not set linkrate (%d)\n", + SAS_ADDR(child->sas_addr), phy_id, ret); + goto out_free; + } + pr_notice("ex %016llx phy%02d SATA device set linkrate successfully\n", + SAS_ADDR(child->sas_addr), phy_id); + child->linkrate = child->min_linkrate; + } res = sas_get_ata_info(child, phy); if (res) goto out_free; -- cgit v1.2.3 From afd055809b3829bd292ee6ef9b98693d34fcd0f0 Mon Sep 17 00:00:00 2001 From: Otto Sabart Date: Wed, 9 Jan 2019 20:08:56 +0100 Subject: scsi: doc: remove reference to tmscsim.txt file The tmscsim.txt doc file was removed in c121107d0f84. Fixes: c121107d0f84 ("scsi: documentation: Obsolete documentation references") Signed-off-by: Otto Sabart Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 4d5d79d56f4b..85c5c89f2fa5 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1196,8 +1196,6 @@ config SCSI_AM53C974 PCscsi/PCnet (Am53/79C974) solutions. This is a new implementation base on the generic esp_scsi driver. - Documentation can be found in . - Note that this driver does NOT support Tekram DC390W/U/F, which are based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those. -- cgit v1.2.3 From 326a859b28141bcd3445be0606647250742283a6 Mon Sep 17 00:00:00 2001 From: Evan Green Date: Fri, 11 Jan 2019 15:31:59 -0800 Subject: scsi: ufs: Remove select of phy-qcom-ufs from ufs-qcom CONFIG_SCSI_UFS_QCOM selects CONFIG_PHY_QCOM_UFS, assuming that this was the only possible PHY driver Qualcomm's UFS controller would use. But in SDM845, the UFS driver is bundled into phy-qcom-qmp, and phy-qcom-ufs is unused. Remove the select, since for SDM845 it adds useless drivers to the build. Signed-off-by: Evan Green Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 2ddbb26d9c26..6db37cf306b0 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -99,7 +99,6 @@ config SCSI_UFS_DWC_TC_PLATFORM config SCSI_UFS_QCOM tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM - select PHY_QCOM_UFS help This selects the QCOM specific additions to UFSHCD platform driver. UFS host on QCOM needs some vendor specific configuration before -- cgit v1.2.3 From e717f8c6dfec8f76be032fc2a7516de6e31a56a1 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Fri, 11 Jan 2019 13:57:06 -0600 Subject: iio: adc: Add the TI ads124s08 ADC code Introduce the TI ADS124S08 and the ADS124S06 ADC devices from TI. The ADS124S08 is the 12 channel ADC and the ADS124S06 is the 6 channel ADC device These devices share a common datasheet: http://www.ti.com/lit/gpn/ads124s08 Signed-off-by: Dan Murphy Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 10 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ti-ads124s08.c | 376 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 387 insertions(+) create mode 100644 drivers/iio/adc/ti-ads124s08.c (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index f3cc7a31bce5..f782d81137b3 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -935,6 +935,16 @@ config TI_ADS8688 This driver can also be built as a module. If so, the module will be called ti-ads8688. +config TI_ADS124S08 + tristate "Texas Instruments ADS124S08" + depends on SPI && OF + help + If you say yes here you get support for Texas Instruments ADS124S08 + and ADS124S06 ADC chips + + This driver can also be built as a module. If so, the module will be + called ti-ads124s08. + config TI_AM335X_ADC tristate "TI's AM335X ADC driver" depends on MFD_TI_AM335X_TSCADC && HAS_DMA diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ea5031348052..2e7101e8a811 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o +obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c new file mode 100644 index 000000000000..c2cf58908fc8 --- /dev/null +++ b/drivers/iio/adc/ti-ads124s08.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0 +/* TI ADS124S0X chip family driver + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +/* Commands */ +#define ADS124S08_CMD_NOP 0x00 +#define ADS124S08_CMD_WAKEUP 0x02 +#define ADS124S08_CMD_PWRDWN 0x04 +#define ADS124S08_CMD_RESET 0x06 +#define ADS124S08_CMD_START 0x08 +#define ADS124S08_CMD_STOP 0x0a +#define ADS124S08_CMD_SYOCAL 0x16 +#define ADS124S08_CMD_SYGCAL 0x17 +#define ADS124S08_CMD_SFOCAL 0x19 +#define ADS124S08_CMD_RDATA 0x12 +#define ADS124S08_CMD_RREG 0x20 +#define ADS124S08_CMD_WREG 0x40 + +/* Registers */ +#define ADS124S08_ID_REG 0x00 +#define ADS124S08_STATUS 0x01 +#define ADS124S08_INPUT_MUX 0x02 +#define ADS124S08_PGA 0x03 +#define ADS124S08_DATA_RATE 0x04 +#define ADS124S08_REF 0x05 +#define ADS124S08_IDACMAG 0x06 +#define ADS124S08_IDACMUX 0x07 +#define ADS124S08_VBIAS 0x08 +#define ADS124S08_SYS 0x09 +#define ADS124S08_OFCAL0 0x0a +#define ADS124S08_OFCAL1 0x0b +#define ADS124S08_OFCAL2 0x0c +#define ADS124S08_FSCAL0 0x0d +#define ADS124S08_FSCAL1 0x0e +#define ADS124S08_FSCAL2 0x0f +#define ADS124S08_GPIODAT 0x10 +#define ADS124S08_GPIOCON 0x11 + +/* ADS124S0x common channels */ +#define ADS124S08_AIN0 0x00 +#define ADS124S08_AIN1 0x01 +#define ADS124S08_AIN2 0x02 +#define ADS124S08_AIN3 0x03 +#define ADS124S08_AIN4 0x04 +#define ADS124S08_AIN5 0x05 +#define ADS124S08_AINCOM 0x0c +/* ADS124S08 only channels */ +#define ADS124S08_AIN6 0x06 +#define ADS124S08_AIN7 0x07 +#define ADS124S08_AIN8 0x08 +#define ADS124S08_AIN9 0x09 +#define ADS124S08_AIN10 0x0a +#define ADS124S08_AIN11 0x0b +#define ADS124S08_MAX_CHANNELS 12 + +#define ADS124S08_POS_MUX_SHIFT 0x04 +#define ADS124S08_INT_REF 0x09 + +#define ADS124S08_START_REG_MASK 0x1f +#define ADS124S08_NUM_BYTES_MASK 0x1f + +#define ADS124S08_START_CONV 0x01 +#define ADS124S08_STOP_CONV 0x00 + +enum ads124s_id { + ADS124S08_ID, + ADS124S06_ID, +}; + +struct ads124s_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +struct ads124s_private { + const struct ads124s_chip_info *chip_info; + struct gpio_desc *reset_gpio; + struct spi_device *spi; + struct mutex lock; + u8 data[5] ____cacheline_aligned; +}; + +#define ADS124S08_CHAN(index) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 32, \ + .storagebits = 32, \ + }, \ +} + +static const struct iio_chan_spec ads124s06_channels[] = { + ADS124S08_CHAN(0), + ADS124S08_CHAN(1), + ADS124S08_CHAN(2), + ADS124S08_CHAN(3), + ADS124S08_CHAN(4), + ADS124S08_CHAN(5), +}; + +static const struct iio_chan_spec ads124s08_channels[] = { + ADS124S08_CHAN(0), + ADS124S08_CHAN(1), + ADS124S08_CHAN(2), + ADS124S08_CHAN(3), + ADS124S08_CHAN(4), + ADS124S08_CHAN(5), + ADS124S08_CHAN(6), + ADS124S08_CHAN(7), + ADS124S08_CHAN(8), + ADS124S08_CHAN(9), + ADS124S08_CHAN(10), + ADS124S08_CHAN(11), +}; + +static const struct ads124s_chip_info ads124s_chip_info_tbl[] = { + [ADS124S08_ID] = { + .channels = ads124s08_channels, + .num_channels = ARRAY_SIZE(ads124s08_channels), + }, + [ADS124S06_ID] = { + .channels = ads124s06_channels, + .num_channels = ARRAY_SIZE(ads124s06_channels), + }, +}; + +static int ads124s_write_cmd(struct iio_dev *indio_dev, u8 command) +{ + struct ads124s_private *priv = iio_priv(indio_dev); + + priv->data[0] = command; + + return spi_write(priv->spi, &priv->data[0], 1); +} + +static int ads124s_write_reg(struct iio_dev *indio_dev, u8 reg, u8 data) +{ + struct ads124s_private *priv = iio_priv(indio_dev); + + priv->data[0] = ADS124S08_CMD_WREG | reg; + priv->data[1] = 0x0; + priv->data[2] = data; + + return spi_write(priv->spi, &priv->data[0], 3); +} + +static int ads124s_reset(struct iio_dev *indio_dev) +{ + struct ads124s_private *priv = iio_priv(indio_dev); + + if (priv->reset_gpio) { + gpiod_set_value(priv->reset_gpio, 0); + udelay(200); + gpiod_set_value(priv->reset_gpio, 1); + } else { + return ads124s_write_cmd(indio_dev, ADS124S08_CMD_RESET); + } + + return 0; +}; + +static int ads124s_read(struct iio_dev *indio_dev, unsigned int chan) +{ + struct ads124s_private *priv = iio_priv(indio_dev); + int ret; + u32 tmp; + struct spi_transfer t[] = { + { + .tx_buf = &priv->data[0], + .len = 4, + .cs_change = 1, + }, { + .tx_buf = &priv->data[1], + .rx_buf = &priv->data[1], + .len = 4, + }, + }; + + priv->data[0] = ADS124S08_CMD_RDATA; + memset(&priv->data[1], ADS124S08_CMD_NOP, sizeof(priv->data)); + + ret = spi_sync_transfer(priv->spi, t, ARRAY_SIZE(t)); + if (ret < 0) + return ret; + + tmp = priv->data[2] << 16 | priv->data[3] << 8 | priv->data[4]; + + return tmp; +} + +static int ads124s_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long m) +{ + struct ads124s_private *priv = iio_priv(indio_dev); + int ret; + + mutex_lock(&priv->lock); + switch (m) { + case IIO_CHAN_INFO_RAW: + ret = ads124s_write_reg(indio_dev, ADS124S08_INPUT_MUX, + chan->channel); + if (ret) { + dev_err(&priv->spi->dev, "Set ADC CH failed\n"); + goto out; + } + + ret = ads124s_write_cmd(indio_dev, ADS124S08_START_CONV); + if (ret) { + dev_err(&priv->spi->dev, "Start converions failed\n"); + goto out; + } + + ret = ads124s_read(indio_dev, chan->channel); + if (ret < 0) { + dev_err(&priv->spi->dev, "Read ADC failed\n"); + goto out; + } + + *val = ret; + + ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV); + if (ret) { + dev_err(&priv->spi->dev, "Stop converions failed\n"); + goto out; + } + + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } +out: + mutex_unlock(&priv->lock); + return ret; +} + +static const struct iio_info ads124s_info = { + .read_raw = &ads124s_read_raw, +}; + +static irqreturn_t ads124s_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ads124s_private *priv = iio_priv(indio_dev); + u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)]; + int scan_index, j = 0; + int ret; + + for_each_set_bit(scan_index, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = ads124s_write_reg(indio_dev, ADS124S08_INPUT_MUX, + scan_index); + if (ret) + dev_err(&priv->spi->dev, "Set ADC CH failed\n"); + + ret = ads124s_write_cmd(indio_dev, ADS124S08_START_CONV); + if (ret) + dev_err(&priv->spi->dev, "Start ADC converions failed\n"); + + buffer[j] = ads124s_read(indio_dev, scan_index); + ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV); + if (ret) + dev_err(&priv->spi->dev, "Stop ADC converions failed\n"); + + j++; + } + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, + pf->timestamp); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ads124s_probe(struct spi_device *spi) +{ + struct ads124s_private *ads124s_priv; + struct iio_dev *indio_dev; + const struct spi_device_id *spi_id = spi_get_device_id(spi); + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*ads124s_priv)); + if (indio_dev == NULL) + return -ENOMEM; + + ads124s_priv = iio_priv(indio_dev); + + ads124s_priv->reset_gpio = devm_gpiod_get_optional(&spi->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(ads124s_priv->reset_gpio)) + dev_info(&spi->dev, "Reset GPIO not defined\n"); + + ads124s_priv->chip_info = &ads124s_chip_info_tbl[spi_id->driver_data]; + + spi_set_drvdata(spi, indio_dev); + + ads124s_priv->spi = spi; + + indio_dev->name = spi_id->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ads124s_priv->chip_info->channels; + indio_dev->num_channels = ads124s_priv->chip_info->num_channels; + indio_dev->info = &ads124s_info; + + mutex_init(&ads124s_priv->lock); + + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + ads124s_trigger_handler, NULL); + if (ret) { + dev_err(&spi->dev, "iio triggered buffer setup failed\n"); + return ret; + } + + ads124s_reset(indio_dev); + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id ads124s_id[] = { + { "ads124s06", ADS124S06_ID }, + { "ads124s08", ADS124S08_ID }, + { } +}; +MODULE_DEVICE_TABLE(spi, ads124s_id); + +static const struct of_device_id ads124s_of_table[] = { + { .compatible = "ti,ads124s06" }, + { .compatible = "ti,ads124s08" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ads124s_of_table); + +static struct spi_driver ads124s_driver = { + .driver = { + .name = "ads124s08", + .of_match_table = ads124s_of_table, + }, + .probe = ads124s_probe, + .id_table = ads124s_id, +}; +module_spi_driver(ads124s_driver); + +MODULE_AUTHOR("Dan Murphy "); +MODULE_DESCRIPTION("TI TI_ADS12S0X ADC"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 192778fb969c2b9bc33d559b9c7aecdd1498c1ba Mon Sep 17 00:00:00 2001 From: Mircea Caprioru Date: Wed, 9 Jan 2019 11:14:16 +0200 Subject: iio: dac: ad5686: Add support for AD5674R/AD5679R The AD5674R/AD5679R are low power, 16-channel, 12-/16-bit buffered voltage output digital-to-analog converters (DACs). They include a 2.5 V internal reference (enabled by default). These devices are very similar to AD5684R/AD5686R, except that they have 16 channels. Signed-off-by: Mircea Caprioru Signed-off-by: Jonathan Cameron --- drivers/iio/dac/Kconfig | 6 +++--- drivers/iio/dac/ad5686-spi.c | 7 +++++-- drivers/iio/dac/ad5686.c | 42 ++++++++++++++++++++++++++++++++++++++++-- drivers/iio/dac/ad5686.h | 2 ++ 4 files changed, 50 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 851b61eaf3da..f28daf67db6a 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -148,9 +148,9 @@ config AD5686_SPI depends on SPI select AD5686 help - Say yes here to build support for Analog Devices AD5672R, AD5676, - AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R. - Voltage Output Digital to Analog Converter. + Say yes here to build support for Analog Devices AD5672R, AD5674R, + AD5676, AD5676R, AD5679R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, + AD5686R Voltage Output Digital to Analog Converter. To compile this driver as a module, choose M here: the module will be called ad5686. diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 665fa6bd9ced..4d857c8da2d2 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * AD5672R, AD5676, AD5676R, AD5681R, AD5682R, AD5683, AD5683R, - * AD5684, AD5684R, AD5685R, AD5686, AD5686R + * AD5672R, AD5674R, AD5676, AD5676R, AD5679R, + * AD5681R, AD5682R, AD5683, AD5683R, AD5684, + * AD5684R, AD5685R, AD5686, AD5686R * Digital to analog converters driver * * Copyright 2018 Analog Devices Inc. @@ -102,8 +103,10 @@ static int ad5686_spi_remove(struct spi_device *spi) static const struct spi_device_id ad5686_spi_id[] = { {"ad5310r", ID_AD5310R}, {"ad5672r", ID_AD5672R}, + {"ad5674r", ID_AD5674R}, {"ad5676", ID_AD5676}, {"ad5676r", ID_AD5676R}, + {"ad5679r", ID_AD5679R}, {"ad5681r", ID_AD5681R}, {"ad5682r", ID_AD5682R}, {"ad5683", ID_AD5683}, diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index a332b93ca2c4..6dd2759b9092 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -71,7 +71,7 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, int ret; struct ad5686_state *st = iio_priv(indio_dev); unsigned int val, ref_bit_msk; - u8 shift; + u8 shift, address = 0; ret = strtobool(buf, &readin); if (ret) @@ -94,6 +94,9 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, case AD5686_REGMAP: shift = 0; ref_bit_msk = 0; + /* AD5674R/AD5679R have 16 channels and 2 powerdown registers */ + if (chan->channel > 0x7) + address = 0x8; break; case AD5693_REGMAP: shift = 13; @@ -107,7 +110,8 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, if (!st->use_internal_vref) val |= ref_bit_msk; - ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 0, val); + ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, + address, val >> (address * 2)); return ret ? ret : len; } @@ -226,10 +230,32 @@ static struct iio_chan_spec name[] = { \ AD5868_CHANNEL(7, 7, bits, _shift), \ } +#define DECLARE_AD5679_CHANNELS(name, bits, _shift) \ +static struct iio_chan_spec name[] = { \ + AD5868_CHANNEL(0, 0, bits, _shift), \ + AD5868_CHANNEL(1, 1, bits, _shift), \ + AD5868_CHANNEL(2, 2, bits, _shift), \ + AD5868_CHANNEL(3, 3, bits, _shift), \ + AD5868_CHANNEL(4, 4, bits, _shift), \ + AD5868_CHANNEL(5, 5, bits, _shift), \ + AD5868_CHANNEL(6, 6, bits, _shift), \ + AD5868_CHANNEL(7, 7, bits, _shift), \ + AD5868_CHANNEL(8, 8, bits, _shift), \ + AD5868_CHANNEL(9, 9, bits, _shift), \ + AD5868_CHANNEL(10, 10, bits, _shift), \ + AD5868_CHANNEL(11, 11, bits, _shift), \ + AD5868_CHANNEL(12, 12, bits, _shift), \ + AD5868_CHANNEL(13, 13, bits, _shift), \ + AD5868_CHANNEL(14, 14, bits, _shift), \ + AD5868_CHANNEL(15, 15, bits, _shift), \ +} + DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2); DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6); DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); +DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4); DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0); +DECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0); DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4); DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2); DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0); @@ -262,6 +288,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { .num_channels = 8, .regmap_type = AD5686_REGMAP, }, + [ID_AD5674R] = { + .channels = ad5674r_channels, + .int_vref_mv = 2500, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, + }, [ID_AD5675R] = { .channels = ad5676_channels, .int_vref_mv = 2500, @@ -279,6 +311,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { .num_channels = 8, .regmap_type = AD5686_REGMAP, }, + [ID_AD5679R] = { + .channels = ad5679r_channels, + .int_vref_mv = 2500, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, + }, [ID_AD5681R] = { .channels = ad5691r_channels, .int_vref_mv = 2500, diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index 19f6917d4738..4c3e171ce0cc 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -54,9 +54,11 @@ enum ad5686_supported_device_ids { ID_AD5311R, ID_AD5671R, ID_AD5672R, + ID_AD5674R, ID_AD5675R, ID_AD5676, ID_AD5676R, + ID_AD5679R, ID_AD5681R, ID_AD5682R, ID_AD5683, -- cgit v1.2.3 From 1dca9bdec6cbec80de7ddd0f2df05886c1fa82bc Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 8 Jan 2019 09:16:04 +0000 Subject: iio: magnetometer: mag3110: add vdd/vddio regulator operation support The magnetometer's power supplies could be controllable on some platforms, such as i.MX6Q-SABRESD board, the mag3110's power supplies are controlled by a GPIO fixed regulator, need to make sure the regulators are enabled before any communication with mag3110, this patch adds vdd/vddio regulator operation support. Signed-off-by: Anson Huang Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/mag3110.c | 94 ++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index f063355480ba..dd990cdb04a8 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -20,6 +20,7 @@ #include #include #include +#include #define MAG3110_STATUS 0x00 #define MAG3110_OUT_X 0x01 /* MSB first */ @@ -56,6 +57,8 @@ struct mag3110_data { struct mutex lock; u8 ctrl_reg1; int sleep_val; + struct regulator *vdd_reg; + struct regulator *vddio_reg; }; static int mag3110_request(struct mag3110_data *data) @@ -469,17 +472,50 @@ static int mag3110_probe(struct i2c_client *client, struct iio_dev *indio_dev; int ret; - ret = i2c_smbus_read_byte_data(client, MAG3110_WHO_AM_I); - if (ret < 0) - return ret; - if (ret != MAG3110_DEVICE_ID) - return -ENODEV; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); + + data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(data->vdd_reg)) { + if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_err(&client->dev, "failed to get VDD regulator!\n"); + return PTR_ERR(data->vdd_reg); + } + + data->vddio_reg = devm_regulator_get(&client->dev, "vddio"); + if (IS_ERR(data->vddio_reg)) { + if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_err(&client->dev, "failed to get VDDIO regulator!\n"); + return PTR_ERR(data->vddio_reg); + } + + ret = regulator_enable(data->vdd_reg); + if (ret) { + dev_err(&client->dev, "failed to enable VDD regulator!\n"); + return ret; + } + + ret = regulator_enable(data->vddio_reg); + if (ret) { + dev_err(&client->dev, "failed to enable VDDIO regulator!\n"); + goto disable_regulator_vdd; + } + + ret = i2c_smbus_read_byte_data(client, MAG3110_WHO_AM_I); + if (ret < 0) + goto disable_regulators; + if (ret != MAG3110_DEVICE_ID) { + ret = -ENODEV; + goto disable_regulators; + } + data->client = client; mutex_init(&data->lock); @@ -499,7 +535,7 @@ static int mag3110_probe(struct i2c_client *client, ret = mag3110_change_config(data, MAG3110_CTRL_REG1, data->ctrl_reg1); if (ret < 0) - return ret; + goto disable_regulators; ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG2, MAG3110_CTRL_AUTO_MRST_EN); @@ -520,16 +556,24 @@ buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); standby_on_error: mag3110_standby(iio_priv(indio_dev)); +disable_regulators: + regulator_disable(data->vddio_reg); +disable_regulator_vdd: + regulator_disable(data->vdd_reg); + return ret; } static int mag3110_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mag3110_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); mag3110_standby(iio_priv(indio_dev)); + regulator_disable(data->vddio_reg); + regulator_disable(data->vdd_reg); return 0; } @@ -537,14 +581,48 @@ static int mag3110_remove(struct i2c_client *client) #ifdef CONFIG_PM_SLEEP static int mag3110_suspend(struct device *dev) { - return mag3110_standby(iio_priv(i2c_get_clientdata( + struct mag3110_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + int ret; + + ret = mag3110_standby(iio_priv(i2c_get_clientdata( to_i2c_client(dev)))); + if (ret) + return ret; + + ret = regulator_disable(data->vddio_reg); + if (ret) { + dev_err(dev, "failed to disable VDDIO regulator\n"); + return ret; + } + + ret = regulator_disable(data->vdd_reg); + if (ret) { + dev_err(dev, "failed to disable VDD regulator\n"); + return ret; + } + + return 0; } static int mag3110_resume(struct device *dev) { struct mag3110_data *data = iio_priv(i2c_get_clientdata( to_i2c_client(dev))); + int ret; + + ret = regulator_enable(data->vdd_reg); + if (ret) { + dev_err(dev, "failed to enable VDD regulator\n"); + return ret; + } + + ret = regulator_enable(data->vddio_reg); + if (ret) { + dev_err(dev, "failed to enable VDDIO regulator\n"); + regulator_disable(data->vdd_reg); + return ret; + } return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1, data->ctrl_reg1); -- cgit v1.2.3 From 1a02d1239389a9ef81daf4913ce60e9f71f8a61f Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 8 Jan 2019 09:09:39 +0000 Subject: iio: light: isl29018: add vcc regulator operation support The light sensor's power supply could be controllable by regulator on some platforms, such as i.MX6Q-SABRESD board, the light sensor isl29023's power supply is controlled by a GPIO fixed regulator, need to make sure the regulator is enabled before any operation of sensor, this patch adds vcc regulator operation support. Signed-off-by: Anson Huang Signed-off-by: Jonathan Cameron --- drivers/iio/light/isl29018.c | 46 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index b45400f8fef4..846df4dce48c 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,7 @@ struct isl29018_chip { struct isl29018_scale scale; int prox_scheme; bool suspended; + struct regulator *vcc_reg; }; static int isl29018_set_integration_time(struct isl29018_chip *chip, @@ -708,6 +710,16 @@ static const char *isl29018_match_acpi_device(struct device *dev, int *data) return dev_name(dev); } +static void isl29018_disable_regulator_action(void *_data) +{ + struct isl29018_chip *chip = _data; + int err; + + err = regulator_disable(chip->vcc_reg); + if (err) + pr_err("failed to disable isl29018's VCC regulator!\n"); +} + static int isl29018_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -742,6 +754,27 @@ static int isl29018_probe(struct i2c_client *client, chip->scale = isl29018_scales[chip->int_time][0]; chip->suspended = false; + chip->vcc_reg = devm_regulator_get(&client->dev, "vcc"); + if (IS_ERR(chip->vcc_reg)) { + err = PTR_ERR(chip->vcc_reg); + if (err != -EPROBE_DEFER) + dev_err(&client->dev, "failed to get VCC regulator!\n"); + return err; + } + + err = regulator_enable(chip->vcc_reg); + if (err) { + dev_err(&client->dev, "failed to enable VCC regulator!\n"); + return err; + } + + err = devm_add_action_or_reset(&client->dev, isl29018_disable_regulator_action, + chip); + if (err) { + dev_err(&client->dev, "failed to setup regulator cleanup action!\n"); + return err; + } + chip->regmap = devm_regmap_init_i2c(client, isl29018_chip_info_tbl[dev_id].regmap_cfg); if (IS_ERR(chip->regmap)) { @@ -768,6 +801,7 @@ static int isl29018_probe(struct i2c_client *client, static int isl29018_suspend(struct device *dev) { struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); + int ret; mutex_lock(&chip->lock); @@ -777,10 +811,13 @@ static int isl29018_suspend(struct device *dev) * So we do not have much to do here. */ chip->suspended = true; + ret = regulator_disable(chip->vcc_reg); + if (ret) + dev_err(dev, "failed to disable VCC regulator\n"); mutex_unlock(&chip->lock); - return 0; + return ret; } static int isl29018_resume(struct device *dev) @@ -790,6 +827,13 @@ static int isl29018_resume(struct device *dev) mutex_lock(&chip->lock); + err = regulator_enable(chip->vcc_reg); + if (err) { + dev_err(dev, "failed to enable VCC regulator\n"); + mutex_unlock(&chip->lock); + return err; + } + err = isl29018_chip_init(chip); if (!err) chip->suspended = false; -- cgit v1.2.3 From f6ff49b8a3b6f774777a21a5a0725d98dee5f2d1 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 8 Jan 2019 09:14:06 +0000 Subject: iio: accell: mma8452: add vdd/vddio regulator operation support The accelerometer's power supply could be controllable on some platforms, such as i.MX6Q-SABRESD board, the mma8451's power supplies are controlled by a GPIO fixed regulator, need to make sure the regulators are enabled before any communication with mma8451, this patch adds vdd/vddio regulator operation support. Signed-off-by: Anson Huang Acked-by: Martin Kepplinger Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 105 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 421a0a8a1379..302781126bc6 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -31,6 +31,7 @@ #include #include #include +#include #define MMA8452_STATUS 0x00 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) @@ -107,6 +108,8 @@ struct mma8452_data { u8 data_cfg; const struct mma_chip_info *chip_info; int sleep_val; + struct regulator *vdd_reg; + struct regulator *vddio_reg; }; /** @@ -1534,9 +1537,39 @@ static int mma8452_probe(struct i2c_client *client, mutex_init(&data->lock); data->chip_info = match->data; + data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(data->vdd_reg)) { + if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_err(&client->dev, "failed to get VDD regulator!\n"); + return PTR_ERR(data->vdd_reg); + } + + data->vddio_reg = devm_regulator_get(&client->dev, "vddio"); + if (IS_ERR(data->vddio_reg)) { + if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_err(&client->dev, "failed to get VDDIO regulator!\n"); + return PTR_ERR(data->vddio_reg); + } + + ret = regulator_enable(data->vdd_reg); + if (ret) { + dev_err(&client->dev, "failed to enable VDD regulator!\n"); + return ret; + } + + ret = regulator_enable(data->vddio_reg); + if (ret) { + dev_err(&client->dev, "failed to enable VDDIO regulator!\n"); + goto disable_regulator_vdd; + } + ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); if (ret < 0) - return ret; + goto disable_regulators; switch (ret) { case MMA8451_DEVICE_ID: @@ -1549,7 +1582,8 @@ static int mma8452_probe(struct i2c_client *client, break; /* else: fall through */ default: - return -ENODEV; + ret = -ENODEV; + goto disable_regulators; } dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", @@ -1566,13 +1600,13 @@ static int mma8452_probe(struct i2c_client *client, ret = mma8452_reset(client); if (ret < 0) - return ret; + goto disable_regulators; data->data_cfg = MMA8452_DATA_CFG_FS_2G; ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, data->data_cfg); if (ret < 0) - return ret; + goto disable_regulators; /* * By default set transient threshold to max to avoid events if @@ -1581,7 +1615,7 @@ static int mma8452_probe(struct i2c_client *client, ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS, MMA8452_TRANSIENT_THS_MASK); if (ret < 0) - return ret; + goto disable_regulators; if (client->irq) { int irq2; @@ -1595,7 +1629,7 @@ static int mma8452_probe(struct i2c_client *client, MMA8452_CTRL_REG5, data->chip_info->all_events); if (ret < 0) - return ret; + goto disable_regulators; dev_dbg(&client->dev, "using interrupt line INT1\n"); } @@ -1604,11 +1638,11 @@ static int mma8452_probe(struct i2c_client *client, MMA8452_CTRL_REG4, data->chip_info->enabled_events); if (ret < 0) - return ret; + goto disable_regulators; ret = mma8452_trigger_setup(indio_dev); if (ret < 0) - return ret; + goto disable_regulators; } data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | @@ -1661,12 +1695,19 @@ buffer_cleanup: trigger_cleanup: mma8452_trigger_cleanup(indio_dev); +disable_regulators: + regulator_disable(data->vddio_reg); + +disable_regulator_vdd: + regulator_disable(data->vdd_reg); + return ret; } static int mma8452_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mma8452_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); @@ -1678,6 +1719,9 @@ static int mma8452_remove(struct i2c_client *client) mma8452_trigger_cleanup(indio_dev); mma8452_standby(iio_priv(indio_dev)); + regulator_disable(data->vddio_reg); + regulator_disable(data->vdd_reg); + return 0; } @@ -1696,6 +1740,18 @@ static int mma8452_runtime_suspend(struct device *dev) return -EAGAIN; } + ret = regulator_disable(data->vddio_reg); + if (ret) { + dev_err(dev, "failed to disable VDDIO regulator\n"); + return ret; + } + + ret = regulator_disable(data->vdd_reg); + if (ret) { + dev_err(dev, "failed to disable VDD regulator\n"); + return ret; + } + return 0; } @@ -1705,9 +1761,22 @@ static int mma8452_runtime_resume(struct device *dev) struct mma8452_data *data = iio_priv(indio_dev); int ret, sleep_val; + ret = regulator_enable(data->vdd_reg); + if (ret) { + dev_err(dev, "failed to enable VDD regulator\n"); + return ret; + } + + ret = regulator_enable(data->vddio_reg); + if (ret) { + dev_err(dev, "failed to enable VDDIO regulator\n"); + regulator_disable(data->vdd_reg); + return ret; + } + ret = mma8452_active(data); if (ret < 0) - return ret; + goto runtime_resume_failed; ret = mma8452_get_odr_index(data); sleep_val = 1000 / mma8452_samp_freq[ret][0]; @@ -1717,25 +1786,17 @@ static int mma8452_runtime_resume(struct device *dev) msleep_interruptible(sleep_val); return 0; -} -#endif -#ifdef CONFIG_PM_SLEEP -static int mma8452_suspend(struct device *dev) -{ - return mma8452_standby(iio_priv(i2c_get_clientdata( - to_i2c_client(dev)))); -} +runtime_resume_failed: + regulator_disable(data->vddio_reg); + regulator_disable(data->vdd_reg); -static int mma8452_resume(struct device *dev) -{ - return mma8452_active(iio_priv(i2c_get_clientdata( - to_i2c_client(dev)))); + return ret; } #endif static const struct dev_pm_ops mma8452_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mma8452_suspend, mma8452_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(mma8452_runtime_suspend, mma8452_runtime_resume, NULL) }; -- cgit v1.2.3 From 4ad84cb56b0088f62b0369f36451ebb0fe16f423 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 23 Dec 2018 20:17:51 +0200 Subject: mei: squash single_recv_buf into one bit in client properties single_recv_buf member of struct mei_client_properties has a boolean value and can be represented in on bit, to free other 7 bits for another usage. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 2b7f7677f8cc..b7d2487b8409 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -311,7 +311,8 @@ struct mei_client_properties { u8 protocol_version; u8 max_number_of_connections; u8 fixed_address; - u8 single_recv_buf; + u8 single_recv_buf:1; + u8 reserved:7; u32 max_msg_length; } __packed; -- cgit v1.2.3 From 9b0bb07328f2375b2b6d3f8343edb1ee1ed39307 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Sat, 12 Jan 2019 08:56:31 +0000 Subject: soc: imx: Break dependency on SOC_IMX8MQ for GPCv2 Since this is going to be used on more SoCs than just i.MX8MQ, make the dependency here more generic by using ARCH_MXC instead. Also remove the SOC_IMX7D since it is also included by the ARCH_MXC. Signed-off-by: Abel Vesa Reviewed-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/soc/imx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index 2112d18dbb7b..d80f899d22f9 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -2,7 +2,7 @@ menu "i.MX SoC drivers" config IMX_GPCV2_PM_DOMAINS bool "i.MX GPCv2 PM domains" - depends on SOC_IMX7D || SOC_IMX8MQ || (COMPILE_TEST && OF) + depends on ARCH_MXC || (COMPILE_TEST && OF) depends on PM select PM_GENERIC_DOMAINS default y if SOC_IMX7D -- cgit v1.2.3 From fb5fc09cc8033db207803cb4b6d0409505dc0fd4 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 11 Jan 2019 17:44:31 -0800 Subject: Input: tca6416-keypad - use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca6416-keypad.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index dc983ab6c0ad..cdeef180aead 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -219,9 +219,7 @@ static int tca6416_keypad_probe(struct i2c_client *client, return -EINVAL; } - chip = kzalloc(sizeof(struct tca6416_keypad_chip) + - pdata->nbuttons * sizeof(struct tca6416_button), - GFP_KERNEL); + chip = kzalloc(struct_size(chip, buttons, pdata->nbuttons), GFP_KERNEL); input = input_allocate_device(); if (!chip || !input) { error = -ENOMEM; -- cgit v1.2.3 From a73450036e3222ffd1cb20fc4a88832bb17921b8 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sun, 13 Jan 2019 22:30:18 -0800 Subject: Input: mcs_touchkey - use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mcs_touchkey.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index be56d4f262a7..b132662201a4 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -113,9 +113,8 @@ static int mcs_touchkey_probe(struct i2c_client *client, return -EINVAL; } - data = kzalloc(sizeof(struct mcs_touchkey_data) + - sizeof(data->keycodes[0]) * (pdata->key_maxval + 1), - GFP_KERNEL); + data = kzalloc(struct_size(data, keycodes, pdata->key_maxval + 1), + GFP_KERNEL); input_dev = input_allocate_device(); if (!data || !input_dev) { dev_err(&client->dev, "Failed to allocate memory\n"); -- cgit v1.2.3 From 1eb7ea26d12345898d2647e00c1f675204143bef Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 21 Dec 2018 00:45:41 -0800 Subject: Input: mtk-pmic-keys - remove duplicated include from mtk-pmic-keys.c iSOrt includes in alphabetical order and remove duplicated include file linux/kernel.h Signed-off-by: YueHaibing Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mtk-pmic-keys.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c index 02c67a1749fc..8e6ebab05ab4 100644 --- a/drivers/input/keyboard/mtk-pmic-keys.c +++ b/drivers/input/keyboard/mtk-pmic-keys.c @@ -14,18 +14,17 @@ * */ -#include -#include #include #include -#include #include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include +#include #define MTK_PMIC_PWRKEY_RST_EN_MASK 0x1 #define MTK_PMIC_PWRKEY_RST_EN_SHIFT 6 -- cgit v1.2.3 From a2f39dac0decd9943ba14e14fb58535bb149fd4e Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Sun, 13 Jan 2019 23:08:32 -0800 Subject: Input: edt-ft5x06 - add support for Evervision FT5726 Evervision displays are using different Focaltech touchscreen controllers. This commit adds the initial support for the ones using the FT5726 controller. Receiving the touch data is the same as for the GENERIC_FT but the x and y cooridnates are swapped. The main differences are the register addresses where the GAIN and THRESHOLD parameters are stored. Signed-off-by: Marco Felsch Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 44 +++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 1e18ca0d1b4e..1cd5b804a456 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,9 @@ #define M09_REGISTER_NUM_X 0x94 #define M09_REGISTER_NUM_Y 0x95 +#define EV_REGISTER_THRESHOLD 0x40 +#define EV_REGISTER_GAIN 0x41 + #define NO_REGISTER 0xff #define WORK_REGISTER_OPMODE 0x3c @@ -73,6 +77,7 @@ enum edt_ver { EDT_M06, EDT_M09, EDT_M12, + EV_FT, GENERIC_FT, }; @@ -190,6 +195,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: cmd = 0x0; offset = 3; @@ -242,6 +248,10 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) x = ((buf[0] << 8) | buf[1]) & 0x0fff; y = ((buf[2] << 8) | buf[3]) & 0x0fff; + /* The FT5x26 send the y coordinate first */ + if (tsdata->version == EV_FT) + swap(x, y); + id = (buf[2] >> 4) & 0x0f; down = type != TOUCH_EVENT_UP; @@ -275,8 +285,10 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL); + /* fallthrough */ case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: wrbuf[0] = addr; wrbuf[1] = value; @@ -315,8 +327,10 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, } break; + /* fallthrough */ case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: wrbuf[0] = addr; error = edt_ft5x06_ts_readwrite(tsdata->client, 1, @@ -605,8 +619,9 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) tsdata->threshold); edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, tsdata->gain); - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, - tsdata->offset); + if (reg_addr->reg_offset != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, + tsdata->offset); if (reg_addr->reg_report_rate != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, tsdata->report_rate); @@ -867,6 +882,16 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, case 0x5a: /* Solomon Goldentek Display */ snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); break; + case 0x59: /* Evervision Display with FT5xx6 TS */ + tsdata->version = EV_FT; + error = edt_ft5x06_ts_readwrite(client, 1, "\x53", + 1, rdbuf); + if (error) + return error; + strlcpy(fw_version, rdbuf, 1); + snprintf(model_name, EDT_NAME_LEN, + "EVERVISION-FT5726NEi"); + break; default: snprintf(model_name, EDT_NAME_LEN, "generic ft5x06 (%02x)", @@ -912,7 +937,9 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) tsdata->threshold = edt_ft5x06_register_read(tsdata, reg_addr->reg_threshold); tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); - tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); + if (reg_addr->reg_offset != NO_REGISTER) + tsdata->offset = + edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); if (reg_addr->reg_report_rate != NO_REGISTER) tsdata->report_rate = edt_ft5x06_register_read(tsdata, reg_addr->reg_report_rate); @@ -954,6 +981,15 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_num_y = M09_REGISTER_NUM_Y; break; + case EV_FT: + reg_addr->reg_threshold = EV_REGISTER_THRESHOLD; + reg_addr->reg_gain = EV_REGISTER_GAIN; + reg_addr->reg_offset = NO_REGISTER; + reg_addr->reg_num_x = NO_REGISTER; + reg_addr->reg_num_y = NO_REGISTER; + reg_addr->reg_report_rate = NO_REGISTER; + break; + case GENERIC_FT: /* this is a guesswork */ reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; @@ -1155,6 +1191,7 @@ static const struct edt_i2c_chip_data edt_ft6236_data = { static const struct i2c_device_id edt_ft5x06_ts_id[] = { { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, + { .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data }, /* Note no edt- prefix for compatibility with the ft6236.c driver */ { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, { /* sentinel */ } @@ -1167,6 +1204,7 @@ static const struct of_device_id edt_ft5x06_of_match[] = { { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, + { .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data }, /* Note focaltech vendor prefix for compatibility with ft6236.c */ { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, { /* sentinel */ } -- cgit v1.2.3 From 2ebc1919e9a9812903ab684cc53862015987e7a0 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Sun, 13 Jan 2019 23:10:22 -0800 Subject: Input: edt-ft5x06 - add support to update ev-ft5726 registers Currently only the threshold and gain parameters can be read. Signed-off-by: Marco Felsch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 1cd5b804a456..a67915535b47 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -353,9 +353,10 @@ struct edt_ft5x06_attribute { u8 limit_high; u8 addr_m06; u8 addr_m09; + u8 addr_ev; }; -#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \ +#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_ev, \ _limit_low, _limit_high) \ struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ .dattr = __ATTR(_field, _mode, \ @@ -364,6 +365,7 @@ struct edt_ft5x06_attribute { .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ .addr_m06 = _addr_m06, \ .addr_m09 = _addr_m09, \ + .addr_ev = _addr_ev, \ .limit_low = _limit_low, \ .limit_high = _limit_high, \ } @@ -400,6 +402,10 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, addr = attr->addr_m09; break; + case EV_FT: + addr = attr->addr_ev; + break; + default: error = -ENODEV; goto out; @@ -471,6 +477,10 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, addr = attr->addr_m09; break; + case EV_FT: + addr = attr->addr_ev; + break; + default: error = -ENODEV; goto out; @@ -494,16 +504,16 @@ out: /* m06, m09: range 0-31, m12: range 0-5 */ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, - M09_REGISTER_GAIN, 0, 31); + M09_REGISTER_GAIN, EV_REGISTER_GAIN, 0, 31); /* m06, m09: range 0-31, m12: range 0-16 */ static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, - M09_REGISTER_OFFSET, 0, 31); + M09_REGISTER_OFFSET, NO_REGISTER, 0, 31); /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, - M09_REGISTER_THRESHOLD, 0, 255); + M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255); /* m06: range 3 to 14, m12: (0x64: 100Hz) */ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, - NO_REGISTER, 0, 255); + NO_REGISTER, NO_REGISTER, 0, 255); static struct attribute *edt_ft5x06_attrs[] = { &edt_ft5x06_attr_gain.dattr.attr, -- cgit v1.2.3 From b6eba86030bf2fa3abcf9a0e3fb04527330da52e Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Sun, 13 Jan 2019 23:10:50 -0800 Subject: Input: edt-ft5x06 - add offset support for ev-ft5726 Unfortunately the evervision focaltech implementation uses two offset registers, one for the x coordinate and one for y. This patch extends the driver to handle those offset registers only for devices that support these. Signed-off-by: Marco Felsch Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index a67915535b47..702bfda7ee77 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -56,6 +56,8 @@ #define EV_REGISTER_THRESHOLD 0x40 #define EV_REGISTER_GAIN 0x41 +#define EV_REGISTER_OFFSET_Y 0x45 +#define EV_REGISTER_OFFSET_X 0x46 #define NO_REGISTER 0xff @@ -86,6 +88,8 @@ struct edt_reg_addr { int reg_report_rate; int reg_gain; int reg_offset; + int reg_offset_x; + int reg_offset_y; int reg_num_x; int reg_num_y; }; @@ -111,6 +115,8 @@ struct edt_ft5x06_ts_data { int threshold; int gain; int offset; + int offset_x; + int offset_y; int report_rate; int max_support_points; @@ -508,6 +514,12 @@ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, /* m06, m09: range 0-31, m12: range 0-16 */ static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, M09_REGISTER_OFFSET, NO_REGISTER, 0, 31); +/* m06, m09, m12: no supported, ev_ft: range 0-80 */ +static EDT_ATTR(offset_x, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, + EV_REGISTER_OFFSET_X, 0, 80); +/* m06, m09, m12: no supported, ev_ft: range 0-80 */ +static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, + EV_REGISTER_OFFSET_Y, 0, 80); /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255); @@ -518,6 +530,8 @@ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, static struct attribute *edt_ft5x06_attrs[] = { &edt_ft5x06_attr_gain.dattr.attr, &edt_ft5x06_attr_offset.dattr.attr, + &edt_ft5x06_attr_offset_x.dattr.attr, + &edt_ft5x06_attr_offset_y.dattr.attr, &edt_ft5x06_attr_threshold.dattr.attr, &edt_ft5x06_attr_report_rate.dattr.attr, NULL @@ -632,6 +646,12 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) if (reg_addr->reg_offset != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, tsdata->offset); + if (reg_addr->reg_offset_x != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, + tsdata->offset_x); + if (reg_addr->reg_offset_y != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, + tsdata->offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, tsdata->report_rate); @@ -937,6 +957,18 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev, edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val); tsdata->offset = val; } + + error = device_property_read_u32(dev, "offset-x", &val); + if (!error) { + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, val); + tsdata->offset_x = val; + } + + error = device_property_read_u32(dev, "offset-y", &val); + if (!error) { + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, val); + tsdata->offset_y = val; + } } static void @@ -950,6 +982,12 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) if (reg_addr->reg_offset != NO_REGISTER) tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); + if (reg_addr->reg_offset_x != NO_REGISTER) + tsdata->offset_x = edt_ft5x06_register_read(tsdata, + reg_addr->reg_offset_x); + if (reg_addr->reg_offset_y != NO_REGISTER) + tsdata->offset_y = edt_ft5x06_register_read(tsdata, + reg_addr->reg_offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) tsdata->report_rate = edt_ft5x06_register_read(tsdata, reg_addr->reg_report_rate); @@ -977,6 +1015,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; reg_addr->reg_gain = WORK_REGISTER_GAIN; reg_addr->reg_offset = WORK_REGISTER_OFFSET; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; reg_addr->reg_num_x = WORK_REGISTER_NUM_X; reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; break; @@ -987,6 +1027,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_report_rate = NO_REGISTER; reg_addr->reg_gain = M09_REGISTER_GAIN; reg_addr->reg_offset = M09_REGISTER_OFFSET; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; reg_addr->reg_num_x = M09_REGISTER_NUM_X; reg_addr->reg_num_y = M09_REGISTER_NUM_Y; break; @@ -995,6 +1037,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_threshold = EV_REGISTER_THRESHOLD; reg_addr->reg_gain = EV_REGISTER_GAIN; reg_addr->reg_offset = NO_REGISTER; + reg_addr->reg_offset_x = EV_REGISTER_OFFSET_X; + reg_addr->reg_offset_y = EV_REGISTER_OFFSET_Y; reg_addr->reg_num_x = NO_REGISTER; reg_addr->reg_num_y = NO_REGISTER; reg_addr->reg_report_rate = NO_REGISTER; @@ -1005,6 +1049,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; reg_addr->reg_gain = M09_REGISTER_GAIN; reg_addr->reg_offset = M09_REGISTER_OFFSET; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; break; } } -- cgit v1.2.3 From 6daae00243e622dd3feec7965bfe421ad6dd317e Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 12 Jan 2019 13:59:13 +0100 Subject: pinctrl: meson: meson8b: add the eth_rxd2 and eth_rxd3 pins Gigabit Ethernet requires the Ethernet TXD0..3 and RXD0..3 data lines. Add the missing eth_rxd2 and eth_rxd3 definitions so we don't have to rely on the bootloader to set them up correctly. The vendor u-boot sources for Odroid-C1 use the following Ethernet pinmux configuration: SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, 0x3f4f); SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_7, 0xf00000); This translates to the following pin groups in the mainline kernel: - register 6 bit 0: eth_rxd1 (DIF_0_P) - register 6 bit 1: eth_rxd0 (DIF_0_N) - register 6 bit 2: eth_rx_dv (DIF_1_P) - register 6 bit 3: eth_rx_clk (DIF_1_N) - register 6 bit 6: eth_tx_en (DIF_3_P) - register 6 bit 8: eth_ref_clk (DIF_3_N) - register 6 bit 9: eth_mdc (DIF_4_P) - register 6 bit 10: eth_mdio_en (DIF_4_N) - register 6 bit 11: eth_tx_clk (GPIOH_9) - register 6 bit 12: eth_txd2 (GPIOH_8) - register 6 bit 13: eth_txd3 (GPIOH_7) - register 7 bit 20: eth_txd0_0 (GPIOH_6) - register 7 bit 21: eth_txd1_0 (GPIOH_5) - register 7 bit 22: eth_rxd3 (DIF_2_P) - register 7 bit 23: eth_rxd2 (DIF_2_N) All functions except eth_rxd2 and eth_rxd3 are already supported by the pinctrl-meson8b driver. Suggested-by: Jianxin Pan Signed-off-by: Martin Blumenstingl Reviewed-by: Kevin Hilman Tested-by: Emiliano Ingrassia Reviewed-by: Emiliano Ingrassia Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/pinctrl-meson8b.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c index c69ca95b1ad5..84938bd73ac2 100644 --- a/drivers/pinctrl/meson/pinctrl-meson8b.c +++ b/drivers/pinctrl/meson/pinctrl-meson8b.c @@ -346,6 +346,8 @@ static const unsigned int eth_rx_dv_pins[] = { DIF_1_P }; static const unsigned int eth_rx_clk_pins[] = { DIF_1_N }; static const unsigned int eth_txd0_1_pins[] = { DIF_2_P }; static const unsigned int eth_txd1_1_pins[] = { DIF_2_N }; +static const unsigned int eth_rxd3_pins[] = { DIF_2_P }; +static const unsigned int eth_rxd2_pins[] = { DIF_2_N }; static const unsigned int eth_tx_en_pins[] = { DIF_3_P }; static const unsigned int eth_ref_clk_pins[] = { DIF_3_N }; static const unsigned int eth_mdc_pins[] = { DIF_4_P }; @@ -599,6 +601,8 @@ static struct meson_pmx_group meson8b_cbus_groups[] = { GROUP(eth_ref_clk, 6, 8), GROUP(eth_mdc, 6, 9), GROUP(eth_mdio_en, 6, 10), + GROUP(eth_rxd3, 7, 22), + GROUP(eth_rxd2, 7, 23), }; static struct meson_pmx_group meson8b_aobus_groups[] = { @@ -748,7 +752,7 @@ static const char * const ethernet_groups[] = { "eth_tx_clk", "eth_tx_en", "eth_txd1_0", "eth_txd1_1", "eth_txd0_0", "eth_txd0_1", "eth_rx_clk", "eth_rx_dv", "eth_rxd1", "eth_rxd0", "eth_mdio_en", "eth_mdc", "eth_ref_clk", - "eth_txd2", "eth_txd3" + "eth_txd2", "eth_txd3", "eth_rxd3", "eth_rxd2" }; static const char * const i2c_a_groups[] = { -- cgit v1.2.3 From 6f9c104b183a5a4115a3999ddda6049cbfdbfbbc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 10 Jan 2019 17:38:55 +0200 Subject: APEI / ERST: Switch to use new generic UUID API There are new types and helpers that are supposed to be used in new code. As a preparation to get rid of legacy types and API functions do the conversion here. Signed-off-by: Andy Shevchenko Reviewed-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/erst.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 9953e50667ec..389d88e35ffb 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -938,17 +938,17 @@ static struct pstore_info erst_info = { }; #define CPER_CREATOR_PSTORE \ - UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \ - 0x64, 0x90, 0xb8, 0x9d) + GUID_INIT(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \ + 0x64, 0x90, 0xb8, 0x9d) #define CPER_SECTION_TYPE_DMESG \ - UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \ - 0x94, 0x19, 0xeb, 0x12) + GUID_INIT(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \ + 0x94, 0x19, 0xeb, 0x12) #define CPER_SECTION_TYPE_DMESG_Z \ - UUID_LE(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \ - 0x34, 0xdd, 0xfa, 0xc6) + GUID_INIT(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \ + 0x34, 0xdd, 0xfa, 0xc6) #define CPER_SECTION_TYPE_MCE \ - UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \ - 0x04, 0x4a, 0x38, 0xfc) + GUID_INIT(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \ + 0x04, 0x4a, 0x38, 0xfc) struct cper_pstore_record { struct cper_record_header hdr; @@ -1012,7 +1012,7 @@ skip: rc = -EIO; goto out; } - if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) + if (!guid_equal(&rcd->hdr.creator_id, &CPER_CREATOR_PSTORE)) goto skip; record->buf = kmalloc(len, GFP_KERNEL); @@ -1024,15 +1024,12 @@ skip: record->id = record_id; record->compressed = false; record->ecc_notice_size = 0; - if (uuid_le_cmp(rcd->sec_hdr.section_type, - CPER_SECTION_TYPE_DMESG_Z) == 0) { + if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_DMESG_Z)) { record->type = PSTORE_TYPE_DMESG; record->compressed = true; - } else if (uuid_le_cmp(rcd->sec_hdr.section_type, - CPER_SECTION_TYPE_DMESG) == 0) + } else if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_DMESG)) record->type = PSTORE_TYPE_DMESG; - else if (uuid_le_cmp(rcd->sec_hdr.section_type, - CPER_SECTION_TYPE_MCE) == 0) + else if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_MCE)) record->type = PSTORE_TYPE_MCE; else record->type = PSTORE_TYPE_MAX; -- cgit v1.2.3 From 98a455d91e7116ca417bc37da6aa2dd633206a6f Mon Sep 17 00:00:00 2001 From: Shunyong Yang Date: Tue, 18 Dec 2018 14:02:45 +0800 Subject: ACPI / tables: table override from built-in initrd In some scenario, we need to build initrd with kernel in a single image. This can simplify system deployment process by downloading the whole system once, such as in IC verification. This patch adds support to override ACPI tables from built-in initrd. Signed-off-by: Shunyong Yang [ rjw: Minor cleanups ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 10 ++++++++++ drivers/acpi/tables.c | 12 ++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 90ff0a47c12e..4e015c77e48e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -357,6 +357,16 @@ config ACPI_TABLE_UPGRADE initrd, therefore it's safe to say Y. See Documentation/acpi/initrd_table_override.txt for details +config ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD + bool "Override ACPI tables from built-in initrd" + depends on ACPI_TABLE_UPGRADE + depends on INITRAMFS_SOURCE!="" && INITRAMFS_COMPRESSION="" + help + This option provides functionality to override arbitrary ACPI tables + from built-in uncompressed initrd. + + See Documentation/acpi/initrd_table_override.txt for details + config ACPI_DEBUG bool "Debug Statements" help diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 48eabb6c2d4f..8fccbe49612a 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -473,14 +473,22 @@ static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES); void __init acpi_table_upgrade(void) { - void *data = (void *)initrd_start; - size_t size = initrd_end - initrd_start; + void *data; + size_t size; int sig, no, table_nr = 0, total_offset = 0; long offset = 0; struct acpi_table_header *table; char cpio_path[32] = "kernel/firmware/acpi/"; struct cpio_data file; + if (IS_ENABLED(CONFIG_ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD)) { + data = __initramfs_start; + size = __initramfs_size; + } else { + data = (void *)initrd_start; + size = initrd_end - initrd_start; + } + if (data == NULL || size == 0) return; -- cgit v1.2.3 From f3355298fc5a24eb7606448bc02a08b3485e5979 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Mon, 12 Nov 2018 19:00:55 +0000 Subject: ACPI / APEI: Fix parsing HEST that includes Deferred Machine Check subtable ACPI 6.2 includes a new definition for a Deferred Machine Check "DMC" subtable. The definition of this subtable was included in following commit: c042933df2b1 (ACPICA: Add support for new HEST subtable) However, the HEST parsing function was not updated to include this new subtable. Therefore, Linux will fail to parse the HEST on systems that include a DMC entry. Add the length check for the new DMC subtable so that HEST parsing doesn't fail on systems that include it. Signed-off-by: Yazen Ghannam Reviewed-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/hest.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index b1e9f81ebeea..0935a0ef37e5 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -53,6 +53,7 @@ static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = { [ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge), [ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic), [ACPI_HEST_TYPE_GENERIC_ERROR_V2] = sizeof(struct acpi_hest_generic_v2), + [ACPI_HEST_TYPE_IA32_DEFERRED_CHECK] = -1, }; static int hest_esrc_len(struct acpi_hest_header *hest_hdr) @@ -75,6 +76,11 @@ static int hest_esrc_len(struct acpi_hest_header *hest_hdr) mc = (struct acpi_hest_ia_machine_check *)hest_hdr; len = sizeof(*mc) + mc->num_hardware_banks * sizeof(struct acpi_hest_ia_error_bank); + } else if (hest_type == ACPI_HEST_TYPE_IA32_DEFERRED_CHECK) { + struct acpi_hest_ia_deferred_check *mc; + mc = (struct acpi_hest_ia_deferred_check *)hest_hdr; + len = sizeof(*mc) + mc->num_hardware_banks * + sizeof(struct acpi_hest_ia_error_bank); } BUG_ON(len == -1); -- cgit v1.2.3 From ee9fa8f302dc1df10583fc043a91003e0a332d1b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 2 Jan 2019 13:18:08 +0000 Subject: ACPI: APEI: EINJ: Use DEFINE_DEBUGFS_ATTRIBUTE for debugfs files Use DEFINE_DEBUGFS_ATTRIBUTE rather than DEFINE_SIMPLE_ATTRIBUTE for debugfs files to make debugfs_simple_attr.cocci warnings go away. Semantic patch information: Rationale: DEFINE_SIMPLE_ATTRIBUTE + debugfs_create_file() imposes some significant overhead as compared to DEFINE_DEBUGFS_ATTRIBUTE + debugfs_create_file_unsafe(). Generated by: scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci Signed-off-by: YueHaibing Acked-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/einj.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index fcccbfdbdd1a..6119da1aea4e 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -644,8 +644,8 @@ static int error_type_set(void *data, u64 val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(error_type_fops, error_type_get, - error_type_set, "0x%llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set, + "0x%llx\n"); static int error_inject_set(void *data, u64 val) { @@ -656,8 +656,7 @@ static int error_inject_set(void *data, u64 val) error_param3, error_param4); } -DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, - error_inject_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(error_inject_fops, NULL, error_inject_set, "%llu\n"); static int einj_check_table(struct acpi_table_einj *einj_tab) { @@ -718,12 +717,14 @@ static int __init einj_init(void) if (!fentry) goto err_cleanup; - fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR, - einj_debug_dir, NULL, &error_type_fops); + fentry = debugfs_create_file_unsafe("error_type", 0600, + einj_debug_dir, NULL, + &error_type_fops); if (!fentry) goto err_cleanup; - fentry = debugfs_create_file("error_inject", S_IWUSR, - einj_debug_dir, NULL, &error_inject_fops); + fentry = debugfs_create_file_unsafe("error_inject", 0200, + einj_debug_dir, NULL, + &error_inject_fops); if (!fentry) goto err_cleanup; -- cgit v1.2.3 From 08f0b14adc7c4fd5ef7ab2f4b7a62ed1b8216bbb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 13 Jan 2019 22:17:46 +0800 Subject: regulator: hi655x: Removed unused ctrl_regs field from struct hi655x_regulator The ctrl_regs field is not used at all, remove it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/hi655x-regulator.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/hi655x-regulator.c b/drivers/regulator/hi655x-regulator.c index 36ae54b53814..bba24a6fdb1e 100644 --- a/drivers/regulator/hi655x-regulator.c +++ b/drivers/regulator/hi655x-regulator.c @@ -28,7 +28,6 @@ struct hi655x_regulator { unsigned int disable_reg; unsigned int status_reg; - unsigned int ctrl_regs; unsigned int ctrl_mask; struct regulator_desc rdesc; }; -- cgit v1.2.3 From 638aef7a776a1a78247dbfd387481716bd40bf82 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 12 Jan 2019 12:30:13 +0800 Subject: regulator: pwm: No need to make a copy of regulator_ops per instance Having instance specific copy of desc is enough to support multiple instance of pwm regulator. The regulator_ops is never changed so no need to copy it per instance, make pwm_regulator_voltage_table_ops and pwm_regulator_voltage_continuous_ops const to ensure they won't be changed. The pwm_regulator_desc is a template to be copied so also make it const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index a2fd140eff81..3f53f9134b32 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -40,9 +40,6 @@ struct pwm_regulator_data { /* regulator descriptor */ struct regulator_desc desc; - /* Regulator ops */ - struct regulator_ops ops; - int state; /* Enable GPIO */ @@ -231,7 +228,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, return 0; } -static struct regulator_ops pwm_regulator_voltage_table_ops = { +static const struct regulator_ops pwm_regulator_voltage_table_ops = { .set_voltage_sel = pwm_regulator_set_voltage_sel, .get_voltage_sel = pwm_regulator_get_voltage_sel, .list_voltage = pwm_regulator_list_voltage, @@ -241,7 +238,7 @@ static struct regulator_ops pwm_regulator_voltage_table_ops = { .is_enabled = pwm_regulator_is_enabled, }; -static struct regulator_ops pwm_regulator_voltage_continuous_ops = { +static const struct regulator_ops pwm_regulator_voltage_continuous_ops = { .get_voltage = pwm_regulator_get_voltage, .set_voltage = pwm_regulator_set_voltage, .enable = pwm_regulator_enable, @@ -249,7 +246,7 @@ static struct regulator_ops pwm_regulator_voltage_continuous_ops = { .is_enabled = pwm_regulator_is_enabled, }; -static struct regulator_desc pwm_regulator_desc = { +static const struct regulator_desc pwm_regulator_desc = { .name = "pwm-regulator", .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, @@ -287,9 +284,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, drvdata->state = -EINVAL; drvdata->duty_cycle_table = duty_cycle_table; - memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops, - sizeof(drvdata->ops)); - drvdata->desc.ops = &drvdata->ops; + drvdata->desc.ops = &pwm_regulator_voltage_table_ops; drvdata->desc.n_voltages = length / sizeof(*duty_cycle_table); return 0; @@ -301,9 +296,7 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, u32 dutycycle_range[2] = { 0, 100 }; u32 dutycycle_unit = 100; - memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops, - sizeof(drvdata->ops)); - drvdata->desc.ops = &drvdata->ops; + drvdata->desc.ops = &pwm_regulator_voltage_continuous_ops; drvdata->desc.continuous_voltage_range = true; of_property_read_u32_array(pdev->dev.of_node, -- cgit v1.2.3 From 67cc7ca316c4167cc5aca54b7f63a55de356d976 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 11 Jan 2019 10:58:22 +0800 Subject: regulator: max14577: Remove redundant MODULE_ALIAS The modalias is set by the MODULE_DEVICE_TABLE, thus remove redundant MODULE_ALIAS. Signed-off-by: Axel Lin Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/max14577-regulator.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c index bc7f4751bf9c..85a88a9e4d42 100644 --- a/drivers/regulator/max14577-regulator.c +++ b/drivers/regulator/max14577-regulator.c @@ -324,4 +324,3 @@ module_exit(max14577_regulator_exit); MODULE_AUTHOR("Krzysztof Kozlowski "); MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:max14577-regulator"); -- cgit v1.2.3 From 7085180d6a38197c86a9bea84006fa4a4813c7b7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 9 Jan 2019 17:30:49 +0800 Subject: regulator: twl6030: Use of_device_get_match_data() Use of_device_get_match_data() to simplify the code a bit. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/twl6030-regulator.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c index 219cbd910dbf..78b964539775 100644 --- a/drivers/regulator/twl6030-regulator.c +++ b/drivers/regulator/twl6030-regulator.c @@ -687,14 +687,9 @@ static int twlreg_probe(struct platform_device *pdev) struct regulator_init_data *initdata; struct regulation_constraints *c; struct regulator_dev *rdev; - const struct of_device_id *match; struct regulator_config config = { }; - match = of_match_device(twl_of_match, &pdev->dev); - if (!match) - return -ENODEV; - - template = match->data; + template = of_device_get_match_data(&pdev->dev); if (!template) return -ENODEV; -- cgit v1.2.3 From f01a7beb6791f1c419424c1a6958b7d0a289c974 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 10 Jan 2019 17:26:16 +0800 Subject: regulator: act8865: Fix act8600_sudcdc_voltage_ranges setting The act8600_sudcdc_voltage_ranges setting does not match the datasheet. The problems in below entry: REGULATOR_LINEAR_RANGE(19000000, 191, 255, 400000), 1. The off-by-one min_sel causes wrong volatage calculation. The min_sel should be 192. 2. According to the datasheet[1] Table 7. (on page 43): The selector 248 (0b11111000) ~ 255 (0b11111111) are 41.400V. Also fix off-by-one for ACT8600_SUDCDC_VOLTAGE_NUM. [1] https://active-semi.com/wp-content/uploads/ACT8600_Datasheet.pdf Fixes: df3a950e4e73 ("regulator: act8865: Add act8600 support") Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/act8865-regulator.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 21e20483bd91..e0239cf3f56d 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -131,7 +131,7 @@ * ACT8865 voltage number */ #define ACT8865_VOLTAGE_NUM 64 -#define ACT8600_SUDCDC_VOLTAGE_NUM 255 +#define ACT8600_SUDCDC_VOLTAGE_NUM 256 struct act8865 { struct regmap *regmap; @@ -222,7 +222,8 @@ static const struct regulator_linear_range act8600_sudcdc_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(3000000, 0, 63, 0), REGULATOR_LINEAR_RANGE(3000000, 64, 159, 100000), REGULATOR_LINEAR_RANGE(12600000, 160, 191, 200000), - REGULATOR_LINEAR_RANGE(19000000, 191, 255, 400000), + REGULATOR_LINEAR_RANGE(19000000, 192, 247, 400000), + REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0), }; static struct regulator_ops act8865_ops = { -- cgit v1.2.3 From 0357a3daada3236da59be5d692f02ae07e2a145e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 10 Jan 2019 13:02:52 -0800 Subject: spi: spi-geni-qcom: Don't initialize completion for normal message We only use this completion when we're doing something that isn't a message transfer. For example, changing CS or aborting/canceling a command. All of those situations properly reinitialize the completion before sending the GENI the special command to change CS or cancel, etc. Given that, let's remove the initialization here. Cc: Girish Mahadevan Cc: Dilip Kota Cc: Alok Chauhan Cc: Douglas Anderson Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/spi/spi-geni-qcom.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index fdb7cb88fb56..c3e9464027d4 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -233,7 +233,6 @@ static int spi_geni_prepare_message(struct spi_master *spi, struct geni_se *se = &mas->se; geni_se_select_mode(se, GENI_SE_FIFO); - reinit_completion(&mas->xfer_done); ret = setup_fifo_params(spi_msg->spi, spi); if (ret) dev_err(mas->dev, "Couldn't select mode %d\n", ret); -- cgit v1.2.3 From de43affed77b1bd9f246235dbd94eb23b07ab657 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 10 Jan 2019 13:02:53 -0800 Subject: spi: spi-geni-qcom: Get rid of forward declaration We don't need this forward declaration. Move the function to where it needed so we can drop it and shave some lines of code. CC: Girish Mahadevan CC: Dilip Kota CC: Alok Chauhan Cc: Douglas Anderson Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/spi/spi-geni-qcom.c | 55 +++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index c3e9464027d4..5f0b0d5bfef4 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -89,9 +89,6 @@ struct spi_geni_master { int irq; }; -static void handle_fifo_timeout(struct spi_master *spi, - struct spi_message *msg); - static int get_spi_clk_cfg(unsigned int speed_hz, struct spi_geni_master *mas, unsigned int *clk_idx, @@ -122,6 +119,32 @@ static int get_spi_clk_cfg(unsigned int speed_hz, return ret; } +static void handle_fifo_timeout(struct spi_master *spi, + struct spi_message *msg) +{ + struct spi_geni_master *mas = spi_master_get_devdata(spi); + unsigned long time_left, flags; + struct geni_se *se = &mas->se; + + spin_lock_irqsave(&mas->lock, flags); + reinit_completion(&mas->xfer_done); + mas->cur_mcmd = CMD_CANCEL; + geni_se_cancel_m_cmd(se); + writel(0, se->base + SE_GENI_TX_WATERMARK_REG); + spin_unlock_irqrestore(&mas->lock, flags); + time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + if (time_left) + return; + + spin_lock_irqsave(&mas->lock, flags); + reinit_completion(&mas->xfer_done); + geni_se_abort_m_cmd(se); + spin_unlock_irqrestore(&mas->lock, flags); + time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + if (!time_left) + dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); +} + static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) { struct spi_geni_master *mas = spi_master_get_devdata(slv->master); @@ -356,32 +379,6 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); } -static void handle_fifo_timeout(struct spi_master *spi, - struct spi_message *msg) -{ - struct spi_geni_master *mas = spi_master_get_devdata(spi); - unsigned long time_left, flags; - struct geni_se *se = &mas->se; - - spin_lock_irqsave(&mas->lock, flags); - reinit_completion(&mas->xfer_done); - mas->cur_mcmd = CMD_CANCEL; - geni_se_cancel_m_cmd(se); - writel(0, se->base + SE_GENI_TX_WATERMARK_REG); - spin_unlock_irqrestore(&mas->lock, flags); - time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); - if (time_left) - return; - - spin_lock_irqsave(&mas->lock, flags); - reinit_completion(&mas->xfer_done); - geni_se_abort_m_cmd(se); - spin_unlock_irqrestore(&mas->lock, flags); - time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); - if (!time_left) - dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); -} - static int spi_geni_transfer_one(struct spi_master *spi, struct spi_device *slv, struct spi_transfer *xfer) -- cgit v1.2.3 From af8cd70a99300a7c3451c76efe1afa8eca37cfce Mon Sep 17 00:00:00 2001 From: William Whistler Date: Mon, 14 Jan 2019 17:50:07 +0000 Subject: Support for Maltron L90 keyboard media keys The USB report descriptor sent by the Maltron L90 keyboard is invalid, causing the media key reports not to be accepted. This patch adds a driver which uses a report fixup to replace the descriptor. Signed-off-by: William Whistler Signed-off-by: Benjamin Tissoires --- drivers/hid/Kconfig | 7 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-maltron.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 drivers/hid/hid-maltron.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 41e9935fc584..661fe610ee5b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -590,6 +590,13 @@ config HID_MAGICMOUSE Say Y here if you want support for the multi-touch features of the Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad. +config HID_MALTRON + tristate "Maltron L90 keyboard" + depends on HID + ---help--- + Adds support for the volume up, volume down, mute, and play/pause buttons + of the Maltron L90 keyboard. + config HID_MAYFLASH tristate "Mayflash game controller adapter force feedback" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 896a51ce7ce0..cf2752003253 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o +obj-$(CONFIG_HID_MALTRON) += hid-maltron.o obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 518fa76414f5..01d565357dbe 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -72,6 +72,7 @@ #define USB_VENDOR_ID_ALCOR 0x058f #define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 +#define USB_DEVICE_ID_ALCOR_MALTRON_KB 0x9410 #define USB_VENDOR_ID_ALPS 0x0433 #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 diff --git a/drivers/hid/hid-maltron.c b/drivers/hid/hid-maltron.c new file mode 100644 index 000000000000..dcd6db6a646e --- /dev/null +++ b/drivers/hid/hid-maltron.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * HID driver for Maltron L90 + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2008 Jiri Slaby + * Copyright (c) 2012 David Dillow + * Copyright (c) 2006-2013 Jiri Kosina + * Copyright (c) 2013 Colin Leitner + * Copyright (c) 2014-2016 Frank Praznik + * Copyright (c) 2010 Richard Nauber + * Copyright (c) 2016 Yuxuan Shui + * Copyright (c) 2018 William Whistler + */ + +#include +#include +#include + +#include "hid-ids.h" + +/* The original buggy USB descriptor */ +static u8 maltron_rdesc_o[] = { + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x09, 0x80, /* Usage (Sys Control) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x02, /* Report ID (2) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x01, /* Report Count (1) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x09, 0x82, /* Usage (Sys Sleep) */ + 0x81, 0x06, /* Input (Data,Var,Rel) */ + 0x09, 0x82, /* Usage (Sys Sleep) */ + 0x81, 0x06, /* Input (Data,Var,Rel) */ + 0x09, 0x83, /* Usage (Sys Wake Up) */ + 0x81, 0x06, /* Input (Data,Var,Rel) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input (Const,Array,Abs) */ + 0xC0, /* End Collection */ + 0x05, 0x0C, /* Usage Page (Consumer) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x03, /* Report ID (3) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x10, /* Report Size (16) */ + 0x19, 0x00, /* Usage Minimum (Unassigned) */ + 0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */ + 0x81, 0x00, /* Input (Data,Array,Abs) */ + 0xC0, /* End Collection */ + 0x06, 0x7F, 0xFF, /* Usage Page (Vendor Defined 0xFF7F) */ + 0x09, 0x01, /* Usage (0x01) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x04, /* Report ID (4) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x10, /* Report Size (16) */ + 0x19, 0x00, /* Usage Minimum (0x00) */ + 0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */ + 0x81, 0x00, /* Input (Data,Array,Abs) */ + 0x75, 0x02, /* Report Size (2) */ + 0x25, 0x02, /* Logical Maximum (2) */ + 0x09, 0x90, /* Usage (0x90) */ + 0xB1, 0x02, /* Feature (Data,Var,Abs) */ + 0x75, 0x06, /* Report Size (6) */ + 0xB1, 0x01, /* Feature (Const,Array,Abs) */ + 0x75, 0x01, /* Report Size (1) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x05, 0x08, /* Usage Page (LEDs) */ + 0x09, 0x2A, /* Usage (On-Line) */ + 0x91, 0x02, /* Output (Data,Var,Abs) */ + 0x09, 0x4B, /* Usage (Generic Indicator) */ + 0x91, 0x02, /* Output (Data,Var,Abs) */ + 0x75, 0x06, /* Report Size (6) */ + 0x95, 0x01, /* Report Count (1) */ + 0x91, 0x01, /* Output (Const,Array,Abs) */ + 0xC0 /* End Collection */ +}; + +/* The patched descriptor, allowing media key events to be accepted as valid */ +static u8 maltron_rdesc[] = { + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x09, 0x80, /* Usage (Sys Control) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x02, /* Report ID (2) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x01, /* Report Count (1) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x09, 0x82, /* Usage (Sys Sleep) */ + 0x81, 0x06, /* Input (Data,Var,Rel) */ + 0x09, 0x82, /* Usage (Sys Sleep) */ + 0x81, 0x06, /* Input (Data,Var,Rel) */ + 0x09, 0x83, /* Usage (Sys Wake Up) */ + 0x81, 0x06, /* Input (Data,Var,Rel) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input (Const,Array,Abs) */ + 0xC0, /* End Collection */ + 0x05, 0x0C, /* Usage Page (Consumer) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x03, /* Report ID (3) */ + 0x15, 0x00, /* Logical Minimum (0) - changed */ + 0x26, 0xFF, 0x7F, /* Logical Maximum (32767) - changed */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x10, /* Report Size (16) */ + 0x19, 0x00, /* Usage Minimum (Unassigned) */ + 0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */ + 0x81, 0x00, /* Input (Data,Array,Abs) */ + 0xC0, /* End Collection */ + 0x06, 0x7F, 0xFF, /* Usage Page (Vendor Defined 0xFF7F) */ + 0x09, 0x01, /* Usage (0x01) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x04, /* Report ID (4) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x10, /* Report Size (16) */ + 0x19, 0x00, /* Usage Minimum (0x00) */ + 0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */ + 0x81, 0x00, /* Input (Data,Array,Abs) */ + 0x75, 0x02, /* Report Size (2) */ + 0x25, 0x02, /* Logical Maximum (2) */ + 0x09, 0x90, /* Usage (0x90) */ + 0xB1, 0x02, /* Feature (Data,Var,Abs) */ + 0x75, 0x06, /* Report Size (6) */ + 0xB1, 0x01, /* Feature (Const,Array,Abs) */ + 0x75, 0x01, /* Report Size (1) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x05, 0x08, /* Usage Page (LEDs) */ + 0x09, 0x2A, /* Usage (On-Line) */ + 0x91, 0x02, /* Output (Data,Var,Abs) */ + 0x09, 0x4B, /* Usage (Generic Indicator) */ + 0x91, 0x02, /* Output (Data,Var,Abs) */ + 0x75, 0x06, /* Report Size (6) */ + 0x95, 0x01, /* Report Count (1) */ + 0x91, 0x01, /* Output (Const,Array,Abs) */ + 0xC0 /* End Collection */ +}; + +static __u8 *maltron_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + if (*rsize == sizeof(maltron_rdesc_o) && + !memcmp(maltron_rdesc_o, rdesc, sizeof(maltron_rdesc_o))) { + hid_info(hdev, "Replacing Maltron L90 keyboard report descriptor\n"); + *rsize = sizeof(maltron_rdesc); + return maltron_rdesc; + } + return rdesc; +} + +static const struct hid_device_id maltron_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_MALTRON_KB)}, + { } +}; +MODULE_DEVICE_TABLE(hid, maltron_devices); + +static struct hid_driver maltron_driver = { + .name = "maltron", + .id_table = maltron_devices, + .report_fixup = maltron_report_fixup +}; +module_hid_driver(maltron_driver); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ea4baf7f116a18382df331db2123d98bc1c3cd83 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 18 Dec 2018 14:28:30 +0200 Subject: RDMA: Rename port_callback to init_port Most provider routines are callback routines which ib core invokes. _callback suffix doesn't convey information about when such callback is invoked. Therefore, rename port_callback to init_port. Additionally, store the init_port function pointer in ib_device_ops, so that it can be accessed in subsequent patches when binding rdma device to net namespace. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/core_priv.h | 4 +--- drivers/infiniband/core/device.c | 7 +++---- drivers/infiniband/core/sysfs.c | 16 ++++++---------- drivers/infiniband/hw/bnxt_re/main.c | 2 +- drivers/infiniband/hw/cxgb3/iwch_provider.c | 2 +- drivers/infiniband/hw/cxgb4/provider.c | 2 +- drivers/infiniband/hw/hfi1/verbs.c | 2 +- drivers/infiniband/hw/hns/hns_roce_main.c | 2 +- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 2 +- drivers/infiniband/hw/mlx4/main.c | 2 +- drivers/infiniband/hw/mlx5/main.c | 2 +- drivers/infiniband/hw/mthca/mthca_provider.c | 2 +- drivers/infiniband/hw/nes/nes_verbs.c | 2 +- drivers/infiniband/hw/ocrdma/ocrdma_main.c | 2 +- drivers/infiniband/hw/qedr/main.c | 2 +- drivers/infiniband/hw/qib/qib_verbs.c | 2 +- drivers/infiniband/hw/usnic/usnic_ib_main.c | 2 +- drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c | 2 +- drivers/infiniband/sw/rdmavt/vt.c | 5 ++--- drivers/infiniband/sw/rxe/rxe_verbs.c | 2 +- 20 files changed, 28 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index 3cd830d52967..aca75c74e451 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -54,9 +54,7 @@ struct pkey_index_qp_list { struct list_head qp_list; }; -int ib_device_register_sysfs(struct ib_device *device, - int (*port_callback)(struct ib_device *, - u8, struct kobject *)); +int ib_device_register_sysfs(struct ib_device *device); void ib_device_unregister_sysfs(struct ib_device *device); int ib_device_rename(struct ib_device *ibdev, const char *name); diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 8872453e26c0..66867e92ddea 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -574,9 +574,7 @@ port_cleanup: * callback for each device that is added. @device must be allocated * with ib_alloc_device(). */ -int ib_register_device(struct ib_device *device, const char *name, - int (*port_callback)(struct ib_device *, u8, - struct kobject *)) +int ib_register_device(struct ib_device *device, const char *name) { int ret; struct ib_client *client; @@ -613,7 +611,7 @@ int ib_register_device(struct ib_device *device, const char *name, goto dev_cleanup; } - ret = ib_device_register_sysfs(device, port_callback); + ret = ib_device_register_sysfs(device); if (ret) { dev_warn(&device->dev, "Couldn't register device with driver model\n"); @@ -1283,6 +1281,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops) SET_DEVICE_OP(dev_ops, get_vector_affinity); SET_DEVICE_OP(dev_ops, get_vf_config); SET_DEVICE_OP(dev_ops, get_vf_stats); + SET_DEVICE_OP(dev_ops, init_port); SET_DEVICE_OP(dev_ops, map_mr_sg); SET_DEVICE_OP(dev_ops, map_phys_fmr); SET_DEVICE_OP(dev_ops, mmap); diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 80f68eb0ba5c..7a5679933df6 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -1015,9 +1015,7 @@ err_free_stats: return; } -static int add_port(struct ib_device *device, int port_num, - int (*port_callback)(struct ib_device *, - u8, struct kobject *)) +static int add_port(struct ib_device *device, int port_num) { struct ib_port *p; struct ib_port_attr attr; @@ -1113,8 +1111,8 @@ static int add_port(struct ib_device *device, int port_num, if (ret) goto err_free_pkey; - if (port_callback) { - ret = port_callback(device, port_num, &p->kobj); + if (device->ops.init_port) { + ret = device->ops.init_port(device, port_num, &p->kobj); if (ret) goto err_remove_pkey; } @@ -1308,9 +1306,7 @@ static void free_port_list_attributes(struct ib_device *device) kobject_put(device->ports_kobj); } -int ib_device_register_sysfs(struct ib_device *device, - int (*port_callback)(struct ib_device *, - u8, struct kobject *)) +int ib_device_register_sysfs(struct ib_device *device) { struct device *class_dev = &device->dev; int ret; @@ -1330,12 +1326,12 @@ int ib_device_register_sysfs(struct ib_device *device, } if (rdma_cap_ib_switch(device)) { - ret = add_port(device, 0, port_callback); + ret = add_port(device, 0); if (ret) goto err_put; } else { for (i = 1; i <= device->phys_port_cnt; ++i) { - ret = add_port(device, i, port_callback); + ret = add_port(device, i); if (ret) goto err_put; } diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index e7a997f2a537..797a3e943366 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -662,7 +662,7 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) rdma_set_device_sysfs_group(ibdev, &bnxt_re_dev_attr_group); ibdev->driver_id = RDMA_DRIVER_BNXT_RE; ib_set_device_ops(ibdev, &bnxt_re_dev_ops); - return ib_register_device(ibdev, "bnxt_re%d", NULL); + return ib_register_device(ibdev, "bnxt_re%d"); } static void bnxt_re_dev_remove(struct bnxt_re_dev *rdev) diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 92ee6761a3bd..ffdde3cca268 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1409,7 +1409,7 @@ int iwch_register_device(struct iwch_dev *dev) dev->ibdev.driver_id = RDMA_DRIVER_CXGB3; rdma_set_device_sysfs_group(&dev->ibdev, &iwch_attr_group); ib_set_device_ops(&dev->ibdev, &iwch_dev_ops); - ret = ib_register_device(&dev->ibdev, "cxgb3_%d", NULL); + ret = ib_register_device(&dev->ibdev, "cxgb3_%d"); if (ret) kfree(dev->ibdev.iwcm); return ret; diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 586b0c37481f..0a99894b0160 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -634,7 +634,7 @@ void c4iw_register_device(struct work_struct *work) rdma_set_device_sysfs_group(&dev->ibdev, &c4iw_attr_group); dev->ibdev.driver_id = RDMA_DRIVER_CXGB4; ib_set_device_ops(&dev->ibdev, &c4iw_dev_ops); - ret = ib_register_device(&dev->ibdev, "cxgb4_%d", NULL); + ret = ib_register_device(&dev->ibdev, "cxgb4_%d"); if (ret) goto err_kfree_iwcm; return; diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index ec582d86025f..8957adf58af7 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1622,6 +1622,7 @@ static const struct ib_device_ops hfi1_dev_ops = { .alloc_rdma_netdev = hfi1_vnic_alloc_rn, .get_dev_fw_str = hfi1_get_dev_fw_str, .get_hw_stats = get_hw_stats, + .init_port = hfi1_create_port_files, .modify_device = modify_device, /* keep process mad in the driver */ .process_mad = hfi1_process_mad, @@ -1679,7 +1680,6 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) /* * Fill in rvt info object. */ - dd->verbs_dev.rdi.driver_f.port_callback = hfi1_create_port_files; dd->verbs_dev.rdi.driver_f.get_pci_dev = get_pci_dev; dd->verbs_dev.rdi.driver_f.check_ah = hfi1_check_ah; dd->verbs_dev.rdi.driver_f.notify_new_ah = hfi1_notify_new_ah; diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 44a07fce0617..46ede58ef3b8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -564,7 +564,7 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) ib_dev->driver_id = RDMA_DRIVER_HNS; ib_set_device_ops(ib_dev, hr_dev->hw->hns_roce_dev_ops); ib_set_device_ops(ib_dev, &hns_roce_dev_ops); - ret = ib_register_device(ib_dev, "hns_%d", NULL); + ret = ib_register_device(ib_dev, "hns_%d"); if (ret) { dev_err(dev, "ib_register_device failed!\n"); return ret; diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 80b66df95362..af66ab9d150b 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -2868,7 +2868,7 @@ int i40iw_register_rdma_device(struct i40iw_device *iwdev) iwibdev = iwdev->iwibdev; rdma_set_device_sysfs_group(&iwibdev->ibdev, &i40iw_attr_group); iwibdev->ibdev.driver_id = RDMA_DRIVER_I40IW; - ret = ib_register_device(&iwibdev->ibdev, "i40iw%d", NULL); + ret = ib_register_device(&iwibdev->ibdev, "i40iw%d"); if (ret) goto error; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 1f15ec3e2b83..c3f950d82ed0 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2856,7 +2856,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) rdma_set_device_sysfs_group(&ibdev->ib_dev, &mlx4_attr_group); ibdev->ib_dev.driver_id = RDMA_DRIVER_MLX4; - if (ib_register_device(&ibdev->ib_dev, "mlx4_%d", NULL)) + if (ib_register_device(&ibdev->ib_dev, "mlx4_%d")) goto err_diag_counters; if (mlx4_ib_mad_init(ibdev)) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 717e8535b41a..948617a60d44 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -6233,7 +6233,7 @@ int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev) name = "mlx5_%d"; else name = "mlx5_bond_%d"; - return ib_register_device(&dev->ib_dev, name, NULL); + return ib_register_device(&dev->ib_dev, name); } void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev) diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 0a939ea5497b..3473c6c51b92 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1338,7 +1338,7 @@ int mthca_register_device(struct mthca_dev *dev) rdma_set_device_sysfs_group(&dev->ib_dev, &mthca_attr_group); dev->ib_dev.driver_id = RDMA_DRIVER_MTHCA; - ret = ib_register_device(&dev->ib_dev, "mthca%d", NULL); + ret = ib_register_device(&dev->ib_dev, "mthca%d"); if (ret) return ret; diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index feb4d259aab9..34601f0cbd74 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -3801,7 +3801,7 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev) rdma_set_device_sysfs_group(&nesvnic->nesibdev->ibdev, &nes_attr_group); nesvnic->nesibdev->ibdev.driver_id = RDMA_DRIVER_NES; - ret = ib_register_device(&nesvnic->nesibdev->ibdev, "nes%d", NULL); + ret = ib_register_device(&nesvnic->nesibdev->ibdev, "nes%d"); if (ret) { return ret; } diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index 1f393842453a..f45b996f617f 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -243,7 +243,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev) } rdma_set_device_sysfs_group(&dev->ibdev, &ocrdma_attr_group); dev->ibdev.driver_id = RDMA_DRIVER_OCRDMA; - return ib_register_device(&dev->ibdev, "ocrdma%d", NULL); + return ib_register_device(&dev->ibdev, "ocrdma%d"); } static int ocrdma_alloc_resources(struct ocrdma_dev *dev) diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 75940e2a8791..8e5c76d06855 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -290,7 +290,7 @@ static int qedr_register_device(struct qedr_dev *dev) ib_set_device_ops(&dev->ibdev, &qedr_dev_ops); dev->ibdev.driver_id = RDMA_DRIVER_QEDR; - return ib_register_device(&dev->ibdev, "qedr%d", NULL); + return ib_register_device(&dev->ibdev, "qedr%d"); } /* This function allocates fast-path status block memory */ diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 276304f611ab..ff8dab8e2344 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -1494,6 +1494,7 @@ static void qib_fill_device_attr(struct qib_devdata *dd) } static const struct ib_device_ops qib_dev_ops = { + .init_port = qib_create_port_files, .modify_device = qib_modify_device, .process_mad = qib_process_mad, }; @@ -1567,7 +1568,6 @@ int qib_register_ib_device(struct qib_devdata *dd) /* * Fill in rvt info object. */ - dd->verbs_dev.rdi.driver_f.port_callback = qib_create_port_files; dd->verbs_dev.rdi.driver_f.get_pci_dev = qib_get_pci_dev; dd->verbs_dev.rdi.driver_f.check_ah = qib_check_ah; dd->verbs_dev.rdi.driver_f.setup_wqe = qib_check_send_wqe; diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c index b2323a52a0dd..3201dd1899c7 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_main.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c @@ -422,7 +422,7 @@ static void *usnic_ib_device_add(struct pci_dev *dev) us_ibdev->ib_dev.driver_id = RDMA_DRIVER_USNIC; rdma_set_device_sysfs_group(&us_ibdev->ib_dev, &usnic_attr_group); - if (ib_register_device(&us_ibdev->ib_dev, "usnic_%d", NULL)) + if (ib_register_device(&us_ibdev->ib_dev, "usnic_%d")) goto err_fwd_dealloc; usnic_fwd_set_mtu(us_ibdev->ufdev, us_ibdev->netdev->mtu); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c index eaa109dbc96a..1bc415483d9b 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c @@ -278,7 +278,7 @@ static int pvrdma_register_device(struct pvrdma_dev *dev) spin_lock_init(&dev->srq_tbl_lock); rdma_set_device_sysfs_group(&dev->ib_dev, &pvrdma_attr_group); - ret = ib_register_device(&dev->ib_dev, "vmw_pvrdma%d", NULL); + ret = ib_register_device(&dev->ib_dev, "vmw_pvrdma%d"); if (ret) goto err_srq_free; diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c index 8724a1817158..7de7389d0235 100644 --- a/drivers/infiniband/sw/rdmavt/vt.c +++ b/drivers/infiniband/sw/rdmavt/vt.c @@ -446,7 +446,7 @@ static noinline int check_support(struct rvt_dev_info *rdi, int verb) * These functions are not part of verbs specifically but are * required for rdmavt to function. */ - if ((!rdi->driver_f.port_callback) || + if ((!rdi->ibdev.ops.init_port) || (!rdi->driver_f.get_pci_dev)) return -EINVAL; break; @@ -644,8 +644,7 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id) rdi->ibdev.driver_id = driver_id; /* We are now good to announce we exist */ - ret = ib_register_device(&rdi->ibdev, dev_name(&rdi->ibdev.dev), - rdi->driver_f.port_callback); + ret = ib_register_device(&rdi->ibdev, dev_name(&rdi->ibdev.dev)); if (ret) { rvt_pr_err(rdi, "Failed to register driver with ib core.\n"); goto bail_wss; diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index b20e6e0415f5..43171148e9c5 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -1258,7 +1258,7 @@ int rxe_register_device(struct rxe_dev *rxe) rdma_set_device_sysfs_group(dev, &rxe_attr_group); dev->driver_id = RDMA_DRIVER_RXE; - err = ib_register_device(dev, "rxe%d", NULL); + err = ib_register_device(dev, "rxe%d"); if (err) { pr_warn("%s failed with error %d\n", __func__, err); goto err1; -- cgit v1.2.3 From 54747231150f0dddf68f2ee29ec2970fcc433909 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 18 Dec 2018 14:15:56 +0200 Subject: RDMA: Introduce and use rdma_device_to_ibdev() Introduce and use rdma_device_to_ibdev() API for those drivers which are registering one sysfs group and also use in ib_core. In subsequent patch, device->provider_ibdev one-to-one mapping is no longer holds true during accessing sysfs entries. Therefore, introduce an API rdma_device_to_ibdev() that provides such information. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 2 -- drivers/infiniband/core/sysfs.c | 12 ++++++------ drivers/infiniband/hw/bnxt_re/main.c | 6 ++++-- drivers/infiniband/hw/cxgb3/iwch_provider.c | 14 ++++++++------ drivers/infiniband/hw/cxgb4/provider.c | 14 ++++++++------ drivers/infiniband/hw/hfi1/sysfs.c | 16 ++++++++-------- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 5 ++--- drivers/infiniband/hw/mlx4/main.c | 7 ++++--- drivers/infiniband/hw/mlx5/main.c | 13 ++++++++----- drivers/infiniband/hw/mthca/mthca_provider.c | 9 ++++++--- drivers/infiniband/hw/nes/nes_verbs.c | 2 +- drivers/infiniband/hw/ocrdma/ocrdma_main.c | 6 ++++-- drivers/infiniband/hw/qedr/main.c | 3 ++- drivers/infiniband/hw/qib/qib_sysfs.c | 18 +++++++++--------- drivers/infiniband/hw/usnic/usnic_ib_sysfs.c | 26 +++++++++++--------------- drivers/infiniband/sw/rxe/rxe_verbs.c | 4 ++-- 16 files changed, 83 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 66867e92ddea..f8180cf1a004 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -296,8 +296,6 @@ struct ib_device *ib_alloc_device(size_t size) device->dev.class = &ib_class; device_initialize(&device->dev); - dev_set_drvdata(&device->dev, device); - INIT_LIST_HEAD(&device->event_handler_list); spin_lock_init(&device->event_handler_lock); rwlock_init(&device->client_data_lock); diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 7a5679933df6..c75692802da8 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -1187,7 +1187,7 @@ err_put: static ssize_t node_type_show(struct device *device, struct device_attribute *attr, char *buf) { - struct ib_device *dev = container_of(device, struct ib_device, dev); + struct ib_device *dev = rdma_device_to_ibdev(device); switch (dev->node_type) { case RDMA_NODE_IB_CA: return sprintf(buf, "%d: CA\n", dev->node_type); @@ -1204,7 +1204,7 @@ static DEVICE_ATTR_RO(node_type); static ssize_t sys_image_guid_show(struct device *device, struct device_attribute *dev_attr, char *buf) { - struct ib_device *dev = container_of(device, struct ib_device, dev); + struct ib_device *dev = rdma_device_to_ibdev(device); return sprintf(buf, "%04x:%04x:%04x:%04x\n", be16_to_cpu(((__be16 *) &dev->attrs.sys_image_guid)[0]), @@ -1217,7 +1217,7 @@ static DEVICE_ATTR_RO(sys_image_guid); static ssize_t node_guid_show(struct device *device, struct device_attribute *attr, char *buf) { - struct ib_device *dev = container_of(device, struct ib_device, dev); + struct ib_device *dev = rdma_device_to_ibdev(device); return sprintf(buf, "%04x:%04x:%04x:%04x\n", be16_to_cpu(((__be16 *) &dev->node_guid)[0]), @@ -1230,7 +1230,7 @@ static DEVICE_ATTR_RO(node_guid); static ssize_t node_desc_show(struct device *device, struct device_attribute *attr, char *buf) { - struct ib_device *dev = container_of(device, struct ib_device, dev); + struct ib_device *dev = rdma_device_to_ibdev(device); return sprintf(buf, "%.64s\n", dev->node_desc); } @@ -1239,7 +1239,7 @@ static ssize_t node_desc_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { - struct ib_device *dev = container_of(device, struct ib_device, dev); + struct ib_device *dev = rdma_device_to_ibdev(device); struct ib_device_modify desc = {}; int ret; @@ -1258,7 +1258,7 @@ static DEVICE_ATTR_RW(node_desc); static ssize_t fw_ver_show(struct device *device, struct device_attribute *attr, char *buf) { - struct ib_device *dev = container_of(device, struct ib_device, dev); + struct ib_device *dev = rdma_device_to_ibdev(device); ib_get_device_fw_str(dev, buf); strlcat(buf, "\n", IB_FW_VERSION_NAME_MAX); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 797a3e943366..16eecfa5882c 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -538,7 +538,8 @@ static struct bnxt_en_dev *bnxt_re_dev_probe(struct net_device *netdev) static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf) { - struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev); + struct bnxt_re_dev *rdev = + rdma_device_to_drv_device(device, struct bnxt_re_dev, ibdev); return scnprintf(buf, PAGE_SIZE, "0x%x\n", rdev->en_dev->pdev->vendor); } @@ -547,7 +548,8 @@ static DEVICE_ATTR_RO(hw_rev); static ssize_t hca_type_show(struct device *device, struct device_attribute *attr, char *buf) { - struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev); + struct bnxt_re_dev *rdev = + rdma_device_to_drv_device(device, struct bnxt_re_dev, ibdev); return scnprintf(buf, PAGE_SIZE, "%s\n", rdev->ibdev.node_desc); } diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index ffdde3cca268..07c20cd07f33 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1130,8 +1130,9 @@ static int iwch_query_port(struct ib_device *ibdev, static ssize_t hw_rev_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev, - ibdev.dev); + struct iwch_dev *iwch_dev = + rdma_device_to_drv_device(dev, struct iwch_dev, ibdev); + pr_debug("%s dev 0x%p\n", __func__, dev); return sprintf(buf, "%d\n", iwch_dev->rdev.t3cdev_p->type); } @@ -1140,8 +1141,8 @@ static DEVICE_ATTR_RO(hw_rev); static ssize_t hca_type_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev, - ibdev.dev); + struct iwch_dev *iwch_dev = + rdma_device_to_drv_device(dev, struct iwch_dev, ibdev); struct ethtool_drvinfo info; struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev; @@ -1154,8 +1155,9 @@ static DEVICE_ATTR_RO(hca_type); static ssize_t board_id_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev, - ibdev.dev); + struct iwch_dev *iwch_dev = + rdma_device_to_drv_device(dev, struct iwch_dev, ibdev); + pr_debug("%s dev 0x%p\n", __func__, dev); return sprintf(buf, "%x.%x\n", iwch_dev->rdev.rnic_info.pdev->vendor, iwch_dev->rdev.rnic_info.pdev->device); diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 0a99894b0160..f977f8e7e162 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -376,8 +376,9 @@ static int c4iw_query_port(struct ib_device *ibdev, u8 port, static ssize_t hw_rev_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev, - ibdev.dev); + struct c4iw_dev *c4iw_dev = + rdma_device_to_drv_device(dev, struct c4iw_dev, ibdev); + pr_debug("dev 0x%p\n", dev); return sprintf(buf, "%d\n", CHELSIO_CHIP_RELEASE(c4iw_dev->rdev.lldi.adapter_type)); @@ -387,8 +388,8 @@ static DEVICE_ATTR_RO(hw_rev); static ssize_t hca_type_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev, - ibdev.dev); + struct c4iw_dev *c4iw_dev = + rdma_device_to_drv_device(dev, struct c4iw_dev, ibdev); struct ethtool_drvinfo info; struct net_device *lldev = c4iw_dev->rdev.lldi.ports[0]; @@ -401,8 +402,9 @@ static DEVICE_ATTR_RO(hca_type); static ssize_t board_id_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev, - ibdev.dev); + struct c4iw_dev *c4iw_dev = + rdma_device_to_drv_device(dev, struct c4iw_dev, ibdev); + pr_debug("dev 0x%p\n", dev); return sprintf(buf, "%x.%x\n", c4iw_dev->rdev.lldi.pdev->vendor, c4iw_dev->rdev.lldi.pdev->device); diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c index 2be513d4c9da..90f62c4bddba 100644 --- a/drivers/infiniband/hw/hfi1/sysfs.c +++ b/drivers/infiniband/hw/hfi1/sysfs.c @@ -498,7 +498,7 @@ static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = - container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev); } @@ -508,7 +508,7 @@ static ssize_t board_id_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = - container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); struct hfi1_devdata *dd = dd_from_dev(dev); int ret; @@ -524,7 +524,7 @@ static ssize_t boardversion_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = - container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); struct hfi1_devdata *dd = dd_from_dev(dev); /* The string printed here is already newline-terminated. */ @@ -536,7 +536,7 @@ static ssize_t nctxts_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = - container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); struct hfi1_devdata *dd = dd_from_dev(dev); /* @@ -555,7 +555,7 @@ static ssize_t nfreectxts_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = - container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); struct hfi1_devdata *dd = dd_from_dev(dev); /* Return the number of free user ports (contexts) available. */ @@ -567,7 +567,7 @@ static ssize_t serial_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = - container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); struct hfi1_devdata *dd = dd_from_dev(dev); return scnprintf(buf, PAGE_SIZE, "%s", dd->serial); @@ -579,7 +579,7 @@ static ssize_t chip_reset_store(struct device *device, size_t count) { struct hfi1_ibdev *dev = - container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); struct hfi1_devdata *dd = dd_from_dev(dev); int ret; @@ -609,7 +609,7 @@ static ssize_t tempsense_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = - container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); struct hfi1_devdata *dd = dd_from_dev(dev); struct hfi1_temp temp; int ret; diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index af66ab9d150b..12b31a8440be 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -2139,9 +2139,8 @@ static int i40iw_dereg_mr(struct ib_mr *ib_mr) static ssize_t hw_rev_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct i40iw_ib_device *iwibdev = container_of(dev, - struct i40iw_ib_device, - ibdev.dev); + struct i40iw_ib_device *iwibdev = + rdma_device_to_drv_device(dev, struct i40iw_ib_device, ibdev); u32 hw_rev = iwibdev->iwdev->sc_dev.hw_rev; return sprintf(buf, "%x\n", hw_rev); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index c3f950d82ed0..dc2ffd293a11 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2043,7 +2043,7 @@ static ssize_t hca_type_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx4_ib_dev *dev = - container_of(device, struct mlx4_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mlx4_ib_dev, ib_dev); return sprintf(buf, "MT%d\n", dev->dev->persist->pdev->device); } static DEVICE_ATTR_RO(hca_type); @@ -2052,7 +2052,7 @@ static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx4_ib_dev *dev = - container_of(device, struct mlx4_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mlx4_ib_dev, ib_dev); return sprintf(buf, "%x\n", dev->dev->rev_id); } static DEVICE_ATTR_RO(hw_rev); @@ -2061,7 +2061,8 @@ static ssize_t board_id_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx4_ib_dev *dev = - container_of(device, struct mlx4_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mlx4_ib_dev, ib_dev); + return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, dev->dev->board_id); } diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 948617a60d44..4b1b56d54301 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -4104,7 +4104,7 @@ static ssize_t fw_pages_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = - container_of(device, struct mlx5_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mlx5_ib_dev, ib_dev); return sprintf(buf, "%d\n", dev->mdev->priv.fw_pages); } @@ -4114,7 +4114,7 @@ static ssize_t reg_pages_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = - container_of(device, struct mlx5_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mlx5_ib_dev, ib_dev); return sprintf(buf, "%d\n", atomic_read(&dev->mdev->priv.reg_pages)); } @@ -4124,7 +4124,8 @@ static ssize_t hca_type_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = - container_of(device, struct mlx5_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mlx5_ib_dev, ib_dev); + return sprintf(buf, "MT%d\n", dev->mdev->pdev->device); } static DEVICE_ATTR_RO(hca_type); @@ -4133,7 +4134,8 @@ static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = - container_of(device, struct mlx5_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mlx5_ib_dev, ib_dev); + return sprintf(buf, "%x\n", dev->mdev->rev_id); } static DEVICE_ATTR_RO(hw_rev); @@ -4142,7 +4144,8 @@ static ssize_t board_id_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = - container_of(device, struct mlx5_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mlx5_ib_dev, ib_dev); + return sprintf(buf, "%.*s\n", MLX5_BOARD_ID_LEN, dev->mdev->board_id); } diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 3473c6c51b92..63003b4d2485 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1081,7 +1081,8 @@ static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf) { struct mthca_dev *dev = - container_of(device, struct mthca_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); + return sprintf(buf, "%x\n", dev->rev_id); } static DEVICE_ATTR_RO(hw_rev); @@ -1090,7 +1091,8 @@ static ssize_t hca_type_show(struct device *device, struct device_attribute *attr, char *buf) { struct mthca_dev *dev = - container_of(device, struct mthca_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); + switch (dev->pdev->device) { case PCI_DEVICE_ID_MELLANOX_TAVOR: return sprintf(buf, "MT23108\n"); @@ -1111,7 +1113,8 @@ static ssize_t board_id_show(struct device *device, struct device_attribute *attr, char *buf) { struct mthca_dev *dev = - container_of(device, struct mthca_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); + return sprintf(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id); } static DEVICE_ATTR_RO(board_id); diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 34601f0cbd74..034156f7e9ed 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -2560,7 +2560,7 @@ static ssize_t hw_rev_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nes_ib_device *nesibdev = - container_of(dev, struct nes_ib_device, ibdev.dev); + rdma_device_to_drv_device(dev, struct nes_ib_device, ibdev); struct nes_vnic *nesvnic = nesibdev->nesvnic; nes_debug(NES_DBG_INIT, "\n"); diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index f45b996f617f..b0491b9ecfe4 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -118,7 +118,8 @@ static void get_dev_fw_str(struct ib_device *device, char *str) static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf) { - struct ocrdma_dev *dev = dev_get_drvdata(device); + struct ocrdma_dev *dev = + rdma_device_to_drv_device(device, struct ocrdma_dev, ibdev); return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->nic_info.pdev->vendor); } @@ -127,7 +128,8 @@ static DEVICE_ATTR_RO(hw_rev); static ssize_t hca_type_show(struct device *device, struct device_attribute *attr, char *buf) { - struct ocrdma_dev *dev = dev_get_drvdata(device); + struct ocrdma_dev *dev = + rdma_device_to_drv_device(device, struct ocrdma_dev, ibdev); return scnprintf(buf, PAGE_SIZE, "%s\n", &dev->model_number[0]); } diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 8e5c76d06855..f85e72b65a10 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -137,7 +137,8 @@ static int qedr_iw_port_immutable(struct ib_device *ibdev, u8 port_num, static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf) { - struct qedr_dev *dev = dev_get_drvdata(device); + struct qedr_dev *dev = + rdma_device_to_drv_device(device, struct qedr_dev, ibdev); return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->pdev->vendor); } diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c index 1cf4ca3f23e3..905206a0c2d5 100644 --- a/drivers/infiniband/hw/qib/qib_sysfs.c +++ b/drivers/infiniband/hw/qib/qib_sysfs.c @@ -555,7 +555,7 @@ static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev); } @@ -565,7 +565,7 @@ static ssize_t hca_type_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); struct qib_devdata *dd = dd_from_dev(dev); int ret; @@ -590,7 +590,7 @@ static ssize_t boardversion_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); struct qib_devdata *dd = dd_from_dev(dev); /* The string printed here is already newline-terminated. */ @@ -602,7 +602,7 @@ static ssize_t localbus_info_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); struct qib_devdata *dd = dd_from_dev(dev); /* The string printed here is already newline-terminated. */ @@ -614,7 +614,7 @@ static ssize_t nctxts_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); struct qib_devdata *dd = dd_from_dev(dev); /* Return the number of user ports (contexts) available. */ @@ -630,7 +630,7 @@ static ssize_t nfreectxts_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); struct qib_devdata *dd = dd_from_dev(dev); /* Return the number of free user ports (contexts) available. */ @@ -642,7 +642,7 @@ static ssize_t serial_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); struct qib_devdata *dd = dd_from_dev(dev); buf[sizeof(dd->serial)] = '\0'; @@ -657,7 +657,7 @@ static ssize_t chip_reset_store(struct device *device, size_t count) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); struct qib_devdata *dd = dd_from_dev(dev); int ret; @@ -679,7 +679,7 @@ static ssize_t tempsense_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, rdi.ibdev.dev); + rdma_device_to_drv_device(device, struct qib_ibdev, rdi.ibdev); struct qib_devdata *dd = dd_from_dev(dev); int ret; int idx; diff --git a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c index a7e4b2ccfaf8..c85d48ae7442 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c @@ -50,7 +50,7 @@ static ssize_t board_id_show(struct device *device, struct device_attribute *attr, char *buf) { struct usnic_ib_dev *us_ibdev = - container_of(device, struct usnic_ib_dev, ib_dev.dev); + rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); unsigned short subsystem_device_id; mutex_lock(&us_ibdev->usdev_lock); @@ -67,14 +67,13 @@ static DEVICE_ATTR_RO(board_id); static ssize_t config_show(struct device *device, struct device_attribute *attr, char *buf) { - struct usnic_ib_dev *us_ibdev; + struct usnic_ib_dev *us_ibdev = + rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); char *ptr; unsigned left; unsigned n; enum usnic_vnic_res_type res_type; - us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); - /* Buffer space limit is 1 page */ ptr = buf; left = PAGE_SIZE; @@ -130,9 +129,8 @@ static DEVICE_ATTR_RO(config); static ssize_t iface_show(struct device *device, struct device_attribute *attr, char *buf) { - struct usnic_ib_dev *us_ibdev; - - us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); + struct usnic_ib_dev *us_ibdev = + rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); return scnprintf(buf, PAGE_SIZE, "%s\n", netdev_name(us_ibdev->netdev)); @@ -142,9 +140,8 @@ static DEVICE_ATTR_RO(iface); static ssize_t max_vf_show(struct device *device, struct device_attribute *attr, char *buf) { - struct usnic_ib_dev *us_ibdev; - - us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); + struct usnic_ib_dev *us_ibdev = + rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); return scnprintf(buf, PAGE_SIZE, "%u\n", kref_read(&us_ibdev->vf_cnt)); @@ -154,10 +151,10 @@ static DEVICE_ATTR_RO(max_vf); static ssize_t qp_per_vf_show(struct device *device, struct device_attribute *attr, char *buf) { - struct usnic_ib_dev *us_ibdev; + struct usnic_ib_dev *us_ibdev = + rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); int qp_per_vf; - us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); qp_per_vf = max(us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_WQ], us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_RQ]); @@ -169,9 +166,8 @@ static DEVICE_ATTR_RO(qp_per_vf); static ssize_t cq_per_vf_show(struct device *device, struct device_attribute *attr, char *buf) { - struct usnic_ib_dev *us_ibdev; - - us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); + struct usnic_ib_dev *us_ibdev = + rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); return scnprintf(buf, PAGE_SIZE, "%d\n", us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ]); diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 43171148e9c5..3d01247a28db 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -1129,8 +1129,8 @@ static int rxe_detach_mcast(struct ib_qp *ibqp, union ib_gid *mgid, u16 mlid) static ssize_t parent_show(struct device *device, struct device_attribute *attr, char *buf) { - struct rxe_dev *rxe = container_of(device, struct rxe_dev, - ib_dev.dev); + struct rxe_dev *rxe = + rdma_device_to_drv_device(device, struct rxe_dev, ib_dev); return snprintf(buf, 16, "%s\n", rxe_parent_name(rxe, 1)); } -- cgit v1.2.3 From 97099cc6529cdf50af32a496b588d9428c57341f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 10 Jan 2019 16:00:19 +0300 Subject: RDMA/bnxt_re: fix a size calculation This is from static analysis not from testing. Depending on the value of rcfw->cmdq_depth, then this might not cause an issue at runtime. The BITS_TO_LONGS() macro tells us how many longs it take to hold a bitmap. In other words, it divides by the number if bits per long and rounds up. Then we want to take that number and multiple by sizeof(long) to get the number of bytes to allocate. The code here does the multiplication first so the rounding up is done in the wrong place. So imagine we want to allocate 1 bit, then "(1 * 8) / 64 = 1" when we round up. But it should be "(1 / 64) * 8 = 8". In other words, because of the rounding difference we might allocate up to "sizeof(long) - 1" bytes fewer than intended. Fixes: 1ac5a4047975 ("RDMA/bnxt_re: Add bnxt_re RoCE driver") Signed-off-by: Dan Carpenter Acked-By: Devesh Sharma Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 326805461265..742346ea5b0d 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -684,8 +684,7 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, /* General */ rcfw->seq_num = 0; set_bit(FIRMWARE_FIRST_FLAG, &rcfw->flags); - bmap_size = BITS_TO_LONGS(rcfw->cmdq_depth * - sizeof(unsigned long)); + bmap_size = BITS_TO_LONGS(rcfw->cmdq_depth) * sizeof(unsigned long); rcfw->cmdq_bitmap = kzalloc(bmap_size, GFP_KERNEL); if (!rcfw->cmdq_bitmap) return -ENOMEM; -- cgit v1.2.3 From 734882a8bf984c2ac8a57d8ac3ee53230bd0bed8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 4 Jan 2019 18:08:09 +0000 Subject: spi: cadence: Correct initialisation of runtime PM Currently the driver calls pm_runtime_put_autosuspend but without ever having done a pm_runtime_get, this causes the reference count in the pm runtime core to become -1. The bad reference count causes the core to sometimes suspend whilst an active SPI transfer is in progress. arizona spi0.1: SPI transfer timed out spi_master spi0: failed to transfer one message from queue The correct proceedure is to do all the initialisation that requires the hardware to be powered up before enabling the PM runtime, then enable the PM runtime having called pm_runtime_set_active to inform it that the hardware is currently powered up. The core will then power it down at it's leisure and no explicit pm_runtime_put is required. Fixes: d36ccd9f7ea4 ("spi: cadence: Runtime pm adaptation") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index e332d173dbf9..5036d89f46bb 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -522,11 +522,6 @@ static int cdns_spi_probe(struct platform_device *pdev) goto clk_dis_apb; } - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); if (ret < 0) master->num_chipselect = CDNS_SPI_DEFAULT_NUM_CS; @@ -541,8 +536,10 @@ static int cdns_spi_probe(struct platform_device *pdev) /* SPI controller initializations */ cdns_spi_init_hw(xspi); - pm_runtime_mark_last_busy(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); irq = platform_get_irq(pdev, 0); if (irq <= 0) { -- cgit v1.2.3 From 5fc01fb846bce8fa6d5f95e2625b8ce0f8e86810 Mon Sep 17 00:00:00 2001 From: Myungho Jung Date: Wed, 9 Jan 2019 22:27:31 -0800 Subject: RDMA/cma: Rollback source IP address if failing to acquire device If cma_acquire_dev_by_src_ip() returns error in addr_handler(), the device state changes back to RDMA_CM_ADDR_BOUND but the resolved source IP address is still left. After that, if rdma_destroy_id() is called after rdma_listen(), the device is freed without removed from listen_any_list in cma_cancel_operation(). Revert to the previous IP address if acquiring device fails. Reported-by: syzbot+f3ce716af730c8f96637@syzkaller.appspotmail.com Signed-off-by: Myungho Jung Reviewed-by: Parav Pandit Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 63a7cc00bae0..8cd113b0ddfb 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2963,13 +2963,22 @@ static void addr_handler(int status, struct sockaddr *src_addr, { struct rdma_id_private *id_priv = context; struct rdma_cm_event event = {}; + struct sockaddr *addr; + struct sockaddr_storage old_addr; mutex_lock(&id_priv->handler_mutex); if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_RESOLVED)) goto out; - memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr)); + /* + * Store the previous src address, so that if we fail to acquire + * matching rdma device, old address can be restored back, which helps + * to cancel the cma listen operation correctly. + */ + addr = cma_src_addr(id_priv); + memcpy(&old_addr, addr, rdma_addr_size(addr)); + memcpy(addr, src_addr, rdma_addr_size(src_addr)); if (!status && !id_priv->cma_dev) { status = cma_acquire_dev_by_src_ip(id_priv); if (status) @@ -2980,6 +2989,8 @@ static void addr_handler(int status, struct sockaddr *src_addr, } if (status) { + memcpy(addr, &old_addr, + rdma_addr_size((struct sockaddr *)&old_addr)); if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ADDR_BOUND)) goto out; -- cgit v1.2.3 From 1d09d57728fedd7357ee22d407ae8aae6477757f Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Mon, 14 Jan 2019 21:41:36 +0100 Subject: PCI: Mark expected switch fall-through There is a plan to build the kernel with -Wimplicit-fallthrough and these places in the code produced warnings (W=1). Fix them up. Signed-off-by: Mathieu Malaterre [bhelgaas: squash into one patch, drop extra changelog detail] Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 4 ++-- drivers/pci/quirks.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c9d8e3c837de..94069fc35e91 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -861,7 +861,7 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) need_restore = true; - /* Fall-through: force to D0 */ + /* Fall-through - force to D0 */ default: pmcsr = 0; break; @@ -2260,7 +2260,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup) case PCI_D2: if (pci_no_d1d2(dev)) break; - /* else: fall through */ + /* else, fall through */ default: target_state = state; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b0a413f3f7ca..9fabcef345ed 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2138,7 +2138,7 @@ static void quirk_netmos(struct pci_dev *dev) if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && dev->subsystem_device == 0x0299) return; - /* else: fall through */ + /* else, fall through */ case PCI_DEVICE_ID_NETMOS_9735: case PCI_DEVICE_ID_NETMOS_9745: case PCI_DEVICE_ID_NETMOS_9845: -- cgit v1.2.3 From 25bd879ec16ad3b83a5b1c3f16faa55e696bfccb Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 7 Jan 2019 16:09:40 +0300 Subject: PCI: pciehp: Assign ctrl->slot_ctrl before writing it to hardware Shameerali reported that running v4.20-rc1 as QEMU guest, the PCIe hotplug port times out during boot: pciehp 0000:00:01.0:pcie004: Timeout on hotplug command 0x03f1 (issued 1016 msec ago) pciehp 0000:00:01.0:pcie004: Timeout on hotplug command 0x03f1 (issued 1024 msec ago) pciehp 0000:00:01.0:pcie004: Failed to check link status pciehp 0000:00:01.0:pcie004: Timeout on hotplug command 0x02f1 (issued 2520 msec ago) The issue was bisected down to commit 720d6a671a6e ("PCI: pciehp: Do not handle events if interrupts are masked") and was further analyzed by the reporter to be caused by the fact that pciehp first updates the hardware and only then cache the ctrl->slot_ctrl in pcie_do_write_cmd(). If the interrupt happens before we cache the value, pciehp_isr() reads value 0 and decides that the interrupt was not meant for it causing the above timeout to trigger. Fix by moving ctrl->slot_ctrl assignment to happen before it is written to the hardware. Fixes: 720d6a671a6e ("PCI: pciehp: Do not handle events if interrupts are masked") Link: https://lore.kernel.org/linux-pci/5FC3163CFD30C246ABAA99954A238FA8387DD344@FRAEML521-MBX.china.huawei.com Reported-by: Shameerali Kolothum Thodi Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp_hpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 7dd443aea5a5..cd9eae650aa5 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -156,9 +156,9 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd, slot_ctrl |= (cmd & mask); ctrl->cmd_busy = 1; smp_mb(); + ctrl->slot_ctrl = slot_ctrl; pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl); ctrl->cmd_started = jiffies; - ctrl->slot_ctrl = slot_ctrl; /* * Controllers with the Intel CF118 and similar errata advertise -- cgit v1.2.3 From 557599f14aab2e1e459478c57b5fd83d153189de Mon Sep 17 00:00:00 2001 From: Brajeswar Ghosh Date: Wed, 9 Jan 2019 19:59:59 +0530 Subject: remoteproc/qcom_sysmon.c: Remove duplicate header Remove linux/notifier.h which is included more than once Acked-by: Souptick Joarder Signed-off-by: Brajeswar Ghosh Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_sysmon.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c index e976a602b015..603b813151f2 100644 --- a/drivers/remoteproc/qcom_sysmon.c +++ b/drivers/remoteproc/qcom_sysmon.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 73f5a82bb3c9fce550da4a74a32b8cb064b50663 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 13 Jan 2019 15:57:04 +0200 Subject: RDMA/mad: Reduce MAD scope to mlx5_ib only Management Datagram Interface (MAD) is applicable only when physical port is Infiniband. It makes MAD command logic to be completely unrelated to eth/core parts of mlx5. Signed-off-by: Leon Romanovsky Acked-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cmd.c | 37 ++++++++++++ drivers/infiniband/hw/mlx5/cmd.h | 2 + drivers/infiniband/hw/mlx5/mad.c | 11 ++-- drivers/infiniband/hw/mlx5/mlx5_ib.h | 3 - drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- drivers/net/ethernet/mellanox/mlx5/core/mad.c | 75 ------------------------ 6 files changed, 47 insertions(+), 83 deletions(-) delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/mad.c (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index 356bccc715ee..6bcc63aaa50b 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -345,3 +345,40 @@ int mlx5_cmd_alloc_q_counter(struct mlx5_core_dev *dev, u16 *counter_id, counter_set_id); return err; } + +int mlx5_cmd_mad_ifc(struct mlx5_core_dev *dev, const void *inb, void *outb, + u16 opmod, u8 port) +{ + int outlen = MLX5_ST_SZ_BYTES(mad_ifc_out); + int inlen = MLX5_ST_SZ_BYTES(mad_ifc_in); + int err = -ENOMEM; + void *data; + void *resp; + u32 *out; + u32 *in; + + in = kzalloc(inlen, GFP_KERNEL); + out = kzalloc(outlen, GFP_KERNEL); + if (!in || !out) + goto out; + + MLX5_SET(mad_ifc_in, in, opcode, MLX5_CMD_OP_MAD_IFC); + MLX5_SET(mad_ifc_in, in, op_mod, opmod); + MLX5_SET(mad_ifc_in, in, port, port); + + data = MLX5_ADDR_OF(mad_ifc_in, in, mad); + memcpy(data, inb, MLX5_FLD_SZ_BYTES(mad_ifc_in, mad)); + + err = mlx5_cmd_exec(dev, in, inlen, out, outlen); + if (err) + goto out; + + resp = MLX5_ADDR_OF(mad_ifc_out, out, response_mad_packet); + memcpy(outb, resp, + MLX5_FLD_SZ_BYTES(mad_ifc_out, response_mad_packet)); + +out: + kfree(out); + kfree(in); + return err; +} diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index 1e76dc67a369..923a7b93f507 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -63,4 +63,6 @@ int mlx5_cmd_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn, u16 uid); int mlx5_cmd_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn, u16 uid); int mlx5_cmd_alloc_q_counter(struct mlx5_core_dev *dev, u16 *counter_id, u16 uid); +int mlx5_cmd_mad_ifc(struct mlx5_core_dev *dev, const void *inb, void *outb, + u16 opmod, u8 port); #endif /* MLX5_IB_CMD_H */ diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index 558638468edb..6c529e6f3a01 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -36,6 +36,7 @@ #include #include #include "mlx5_ib.h" +#include "cmd.h" enum { MLX5_IB_VENDOR_CLASS1 = 0x9, @@ -51,9 +52,10 @@ static bool can_do_mad_ifc(struct mlx5_ib_dev *dev, u8 port_num, return dev->mdev->port_caps[port_num - 1].has_smi; } -int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, - u8 port, const struct ib_wc *in_wc, const struct ib_grh *in_grh, - const void *in_mad, void *response_mad) +static int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, + int ignore_bkey, u8 port, const struct ib_wc *in_wc, + const struct ib_grh *in_grh, const void *in_mad, + void *response_mad) { u8 op_modifier = 0; @@ -68,7 +70,8 @@ int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, if (ignore_bkey || !in_wc) op_modifier |= 0x2; - return mlx5_core_mad_ifc(dev->mdev, in_mad, response_mad, op_modifier, port); + return mlx5_cmd_mad_ifc(dev->mdev, in_mad, response_mad, op_modifier, + port); } static int process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index b06d3b1efea8..efe383c0ac86 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -1038,9 +1038,6 @@ void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db) void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq); void mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq); void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index); -int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, - u8 port, const struct ib_wc *in_wc, const struct ib_grh *in_grh, - const void *in_mad, void *response_mad); struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct rdma_ah_attr *ah_attr, u32 flags, struct ib_udata *udata); int mlx5_ib_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 9de9abacf7f6..0257731e6d42 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o # mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ health.o mcg.o cq.o alloc.o qp.o port.o mr.o pd.o \ - mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ + transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \ lib/devcom.o diag/fs_tracepoint.o diag/fw_tracer.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mad.c b/drivers/net/ethernet/mellanox/mlx5/core/mad.c deleted file mode 100644 index 3a3b0005fd2b..000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/mad.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include "mlx5_core.h" - -int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, const void *inb, void *outb, - u16 opmod, u8 port) -{ - int outlen = MLX5_ST_SZ_BYTES(mad_ifc_out); - int inlen = MLX5_ST_SZ_BYTES(mad_ifc_in); - int err = -ENOMEM; - void *data; - void *resp; - u32 *out; - u32 *in; - - in = kzalloc(inlen, GFP_KERNEL); - out = kzalloc(outlen, GFP_KERNEL); - if (!in || !out) - goto out; - - MLX5_SET(mad_ifc_in, in, opcode, MLX5_CMD_OP_MAD_IFC); - MLX5_SET(mad_ifc_in, in, op_mod, opmod); - MLX5_SET(mad_ifc_in, in, port, port); - - data = MLX5_ADDR_OF(mad_ifc_in, in, mad); - memcpy(data, inb, MLX5_FLD_SZ_BYTES(mad_ifc_in, mad)); - - err = mlx5_cmd_exec(dev, in, inlen, out, outlen); - if (err) - goto out; - - resp = MLX5_ADDR_OF(mad_ifc_out, out, response_mad_packet); - memcpy(outb, resp, - MLX5_FLD_SZ_BYTES(mad_ifc_out, response_mad_packet)); - -out: - kfree(out); - kfree(in); - return err; -} -EXPORT_SYMBOL_GPL(mlx5_core_mad_ifc); -- cgit v1.2.3 From baf8b9f8d260c55a86405f70a384c29cda888476 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 15 Jan 2019 12:28:32 +0530 Subject: spi: omap2-mcspi: Fix DMA and FIFO event trigger size mismatch Commit b682cffa3ac6 ("spi: omap2-mcspi: Set FIFO DMA trigger level to word length") broke SPI transfers where bits_per_word != 8. This is because of mimsatch between McSPI FIFO level event trigger size (SPI word length) and DMA request size(word length * maxburst). This leads to data corruption, lockup and errors like: spi1.0: EOW timed out Fix this by setting DMA maxburst size to 1 so that McSPI FIFO level event trigger size matches DMA request size. Fixes: b682cffa3ac6 ("spi: omap2-mcspi: Set FIFO DMA trigger level to word length") Cc: stable@vger.kernel.org Reported-by: David Lechner Tested-by: David Lechner Signed-off-by: Vignesh R Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 2fd8881fcd65..8be304379628 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -623,8 +623,8 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; cfg.src_addr_width = width; cfg.dst_addr_width = width; - cfg.src_maxburst = es; - cfg.dst_maxburst = es; + cfg.src_maxburst = 1; + cfg.dst_maxburst = 1; rx = xfer->rx_buf; tx = xfer->tx_buf; -- cgit v1.2.3 From 63f5ffc46d4f53b309a93b83420b2e4bd0da5aba Mon Sep 17 00:00:00 2001 From: Lanqing Liu Date: Tue, 15 Jan 2019 21:46:50 +0800 Subject: spi: sprd: Fix the error data length in SPI read-only mode In SPI read-only mode, we will always return the writing length, which is always the power of "bits_per_word", but the length unit using by users is byte. Thus this patch fixes the returning length by getting from read_bufs() function to get the correct length. Signed-off-by: Lanqing Liu Signed-off-by: Baolin Wang Signed-off-by: Mark Brown --- drivers/spi/spi-sprd.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index 8daa24eec624..fa324ce194b2 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -380,7 +380,7 @@ static int sprd_spi_txrx_bufs(struct spi_device *sdev, struct spi_transfer *t) { struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller); u32 trans_len = ss->trans_len, len; - int ret, write_size = 0; + int ret, write_size = 0, read_size = 0; while (trans_len) { len = trans_len > SPRD_SPI_FIFO_SIZE ? SPRD_SPI_FIFO_SIZE : @@ -416,13 +416,15 @@ static int sprd_spi_txrx_bufs(struct spi_device *sdev, struct spi_transfer *t) goto complete; if (ss->trans_mode & SPRD_SPI_RX_MODE) - ss->read_bufs(ss, len); + read_size += ss->read_bufs(ss, len); trans_len -= len; } - ret = write_size; - + if (ss->trans_mode & SPRD_SPI_TX_MODE) + ret = write_size; + else + ret = read_size; complete: sprd_spi_enter_idle(ss); -- cgit v1.2.3 From fdb0536469cbc959a044fe61f07e6798d0d08445 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 15 Jan 2019 01:39:29 +0800 Subject: staging: erofs: add document This documents key feature, usage, and on-disk design of erofs. Reviewed-by: Chao Yu Cc: Signed-off-by: Gao Xiang Signed-off-by: Greg Kroah-Hartman --- .../erofs/Documentation/filesystems/erofs.txt | 206 +++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 drivers/staging/erofs/Documentation/filesystems/erofs.txt (limited to 'drivers') diff --git a/drivers/staging/erofs/Documentation/filesystems/erofs.txt b/drivers/staging/erofs/Documentation/filesystems/erofs.txt new file mode 100644 index 000000000000..803988d74c21 --- /dev/null +++ b/drivers/staging/erofs/Documentation/filesystems/erofs.txt @@ -0,0 +1,206 @@ +Overview +======== + +EROFS file-system stands for Enhanced Read-Only File System. Different +from other read-only file systems, it aims to be designed for flexibility, +scalability, but be kept simple and high performance. + +It is designed as a better filesystem solution for the following scenarios: + - read-only storage media or + + - part of a fully trusted read-only solution, which means it needs to be + immutable and bit-for-bit identical to the official golden image for + their releases due to security and other considerations and + + - hope to save some extra storage space with guaranteed end-to-end performance + by using reduced metadata and transparent file compression, especially + for those embedded devices with limited memory (ex, smartphone); + +Here is the main features of EROFS: + - Little endian on-disk design; + + - Currently 4KB block size (nobh) and therefore maximum 16TB address space; + + - Metadata & data could be mixed by design; + + - 2 inode versions for different requirements: + v1 v2 + Inode metadata size: 32 bytes 64 bytes + Max file size: 4 GB 16 EB (also limited by max. vol size) + Max uids/gids: 65536 4294967296 + File creation time: no yes (64 + 32-bit timestamp) + Max hardlinks: 65536 4294967296 + Metadata reserved: 4 bytes 14 bytes + + - Support extended attributes (xattrs) as an option; + + - Support xattr inline and tail-end data inline for all files; + + - Support transparent file compression as an option: + LZ4 algorithm with 4 KB fixed-output compression for high performance; + +The following git tree provides the file system user-space tools under +development (ex, formatting tool mkfs.erofs): +>> git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git + +Bugs and patches are welcome, please kindly help us and send to the following +linux-erofs mailing list: +>> linux-erofs mailing list + +Note that EROFS is still working in progress as a Linux staging driver, +Cc the staging mailing list as well is highly recommended: +>> Linux Driver Project Developer List + +Mount options +============= + +fault_injection=%d Enable fault injection in all supported types with + specified injection rate. Supported injection type: + Type_Name Type_Value + FAULT_KMALLOC 0x000000001 +(no)user_xattr Setup Extended User Attributes. Note: xattr is enabled + by default if CONFIG_EROFS_FS_XATTR is selected. +(no)acl Setup POSIX Access Control List. Note: acl is enabled + by default if CONFIG_EROFS_FS_POSIX_ACL is selected. + +On-disk details +=============== + +Summary +------- +Different from other read-only file systems, an EROFS volume is designed +to be as simple as possible: + + |-> aligned with the block size + ____________________________________________________________ + | |SB| | ... | Metadata | ... | Data | Metadata | ... | Data | + |_|__|_|_____|__________|_____|______|__________|_____|______| + 0 +1K + +All data areas should be aligned with the block size, but metadata areas +may not. All metadatas can be now observed in two different spaces (views): + 1. Inode metadata space + Each valid inode should be aligned with an inode slot, which is a fixed + value (32 bytes) and designed to be kept in line with v1 inode size. + + Each inode can be directly found with the following formula: + inode offset = meta_blkaddr * block_size + 32 * nid + + |-> aligned with 8B + |-> followed closely + + meta_blkaddr blocks |-> another slot + _____________________________________________________________________ + | ... | inode | xattrs | extents | data inline | ... | inode ... + |________|_______|(optional)|(optional)|__(optional)_|_____|__________ + |-> aligned with the inode slot size + . . + . . + . . + . . + . . + . . + .____________________________________________________|-> aligned with 4B + | xattr_ibody_header | shared xattrs | inline xattrs | + |____________________|_______________|_______________| + |-> 12 bytes <-|->x * 4 bytes<-| . + . . . + . . . + . . . + ._______________________________.______________________. + | id | id | id | id | ... | id | ent | ... | ent| ... | + |____|____|____|____|______|____|_____|_____|____|_____| + |-> aligned with 4B + |-> aligned with 4B + + Inode could be 32 or 64 bytes, which can be distinguished from a common + field which all inode versions have -- i_advise: + + __________________ __________________ + | i_advise | | i_advise | + |__________________| |__________________| + | ... | | ... | + | | | | + |__________________| 32 bytes | | + | | + |__________________| 64 bytes + + Xattrs, extents, data inline are followed by the corresponding inode with + proper alignes, and they could be optional for different data mappings, + _currently_ there are totally 3 valid data mappings supported: + + 1) flat file data without data inline (no extent); + 2) fixed-output size data compression (must have extents); + 3) flat file data with tail-end data inline (no extent); + + The size of the optional xattrs is indicated by i_xattr_count in inode + header. Large xattrs or xattrs shared by many different files can be + stored in shared xattrs metadata rather than inlined right after inode. + + 2. Shared xattrs metadata space + Shared xattrs space is similar to the above inode space, started with + a specific block indicated by xattr_blkaddr, organized one by one with + proper align. + + Each share xattr can also be directly found by the following formula: + xattr offset = xattr_blkaddr * block_size + 4 * xattr_id + + |-> aligned by 4 bytes + + xattr_blkaddr blocks |-> aligned with 4 bytes + _________________________________________________________________________ + | ... | xattr_entry | xattr data | ... | xattr_entry | xattr data ... + |________|_____________|_____________|_____|______________|_______________ + +Directories +----------- +All directories are now organized in a compact on-disk format. Note that +each directory block is divided into index and name areas in order to support +random file lookup, and all directory entries are _strictly_ recorded in +alphabetical order in order to support improved prefix binary search +algorithm (could refer to the related source code). + + ___________________________ + / | + / ______________|________________ + / / | nameoff1 | nameoffN-1 + ____________.______________._______________v________________v__________ +| dirent | dirent | ... | dirent | filename | filename | ... | filename | +|___.0___|____1___|_____|___N-1__|____0_____|____1_____|_____|___N-1____| + \ ^ + \ | * could have + \ | trailing '\0' + \________________________| nameoff0 + + Directory block + +Note that apart from the offset of the first filename, nameoff0 also indicates +the total number of directory entries in this block since it is no need to +introduce another on-disk field at all. + +Compression +----------- +Currently, EROFS supports 4KB fixed-output clustersize transparent file +compression, as illustrated below: + + |---- Variant-Length Extent ----|-------- VLE --------|----- VLE ----- + clusterofs clusterofs clusterofs + | | | logical data +_________v_______________________________v_____________________v_______________ +... | . | | . | | . | ... +____|____.________|_____________|________.____|_____________|__.__________|____ + |-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-| + size size size size size + . . . . + . . . . + . . . . + _______._____________._____________._____________._____________________ + ... | | | | ... physical data + _______|_____________|_____________|_____________|_____________________ + |-> cluster <-|-> cluster <-|-> cluster <-| + size size size + +Currently each on-disk physical cluster can contain 4KB (un)compressed data +at most. For each logical cluster, there is a corresponding on-disk index to +describe its cluster type, physical cluster address, etc. + +See "struct z_erofs_vle_decompressed_index" in erofs_fs.h for more details. + -- cgit v1.2.3 From 7077fffcb0b0b65dc75e341306aeef4d0e7f2ec6 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Mon, 14 Jan 2019 19:40:23 +0800 Subject: staging: erofs: fix fast symlink w/o xattr when fs xattr is on Currently, this will hit a BUG_ON for these symlinks as follows: - kernel message ------------[ cut here ]------------ kernel BUG at drivers/staging/erofs/xattr.c:59! SMP PTI CPU: 1 PID: 1170 Comm: getllxattr Not tainted 4.20.0-rc6+ #92 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-2.fc27 04/01/2014 RIP: 0010:init_inode_xattrs+0x22b/0x270 Code: 48 0f 45 ea f0 ff 4d 34 74 0d 41 83 4c 24 e0 01 31 c0 e9 00 fe ff ff 48 89 ef e8 e0 31 9e ff eb e9 89 e8 e9 ef fd ff ff 0f 0$ <0f> 0b 48 89 ef e8 fb f6 9c ff 48 8b 45 08 a8 01 75 24 f0 ff 4d 34 RSP: 0018:ffffa03ac026bdf8 EFLAGS: 00010246 ------------[ cut here ]------------ ... Call Trace: erofs_listxattr+0x30/0x2c0 ? selinux_inode_listxattr+0x5a/0x80 ? kmem_cache_alloc+0x33/0x170 ? security_inode_listxattr+0x27/0x40 listxattr+0xaf/0xc0 path_listxattr+0x5a/0xa0 do_syscall_64+0x43/0xf0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 ... ---[ end trace 3c24b49408dc0c72 ]--- Fix it by checking ->xattr_isize in init_inode_xattrs(), and it also fixes improper return value -ENOTSUPP (it should be -ENODATA if xattr is enabled) for those inodes. Fixes: b17500a0fdba ("staging: erofs: introduce xattr & acl support") Cc: # 4.19+ Reported-by: Li Guifu Tested-by: Li Guifu Reviewed-by: Chao Yu Signed-off-by: Gao Xiang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/inode.c | 8 ++++---- drivers/staging/erofs/xattr.c | 25 ++++++++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/inode.c b/drivers/staging/erofs/inode.c index d7fbf5f4600f..f99954dbfdb5 100644 --- a/drivers/staging/erofs/inode.c +++ b/drivers/staging/erofs/inode.c @@ -185,16 +185,16 @@ static int fill_inode(struct inode *inode, int isdir) /* setup the new inode */ if (S_ISREG(inode->i_mode)) { #ifdef CONFIG_EROFS_FS_XATTR - if (vi->xattr_isize) - inode->i_op = &erofs_generic_xattr_iops; + inode->i_op = &erofs_generic_xattr_iops; #endif inode->i_fop = &generic_ro_fops; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = #ifdef CONFIG_EROFS_FS_XATTR - vi->xattr_isize ? &erofs_dir_xattr_iops : -#endif + &erofs_dir_xattr_iops; +#else &erofs_dir_iops; +#endif inode->i_fop = &erofs_dir_fops; } else if (S_ISLNK(inode->i_mode)) { /* by default, page_get_link is used for symlink */ diff --git a/drivers/staging/erofs/xattr.c b/drivers/staging/erofs/xattr.c index 59bc5641c4e7..1c9498e38f0e 100644 --- a/drivers/staging/erofs/xattr.c +++ b/drivers/staging/erofs/xattr.c @@ -56,7 +56,26 @@ static int init_inode_xattrs(struct inode *inode) return 0; vi = EROFS_V(inode); - BUG_ON(!vi->xattr_isize); + + /* + * bypass all xattr operations if ->xattr_isize is not greater than + * sizeof(struct erofs_xattr_ibody_header), in detail: + * 1) it is not enough to contain erofs_xattr_ibody_header then + * ->xattr_isize should be 0 (it means no xattr); + * 2) it is just to contain erofs_xattr_ibody_header, which is on-disk + * undefined right now (maybe use later with some new sb feature). + */ + if (vi->xattr_isize == sizeof(struct erofs_xattr_ibody_header)) { + errln("xattr_isize %d of nid %llu is not supported yet", + vi->xattr_isize, vi->nid); + return -ENOTSUPP; + } else if (vi->xattr_isize < sizeof(struct erofs_xattr_ibody_header)) { + if (unlikely(vi->xattr_isize)) { + DBG_BUGON(1); + return -EIO; /* xattr ondisk layout error */ + } + return -ENOATTR; + } sb = inode->i_sb; sbi = EROFS_SB(sb); @@ -424,7 +443,6 @@ static int erofs_xattr_generic_get(const struct xattr_handler *handler, struct dentry *unused, struct inode *inode, const char *name, void *buffer, size_t size) { - struct erofs_vnode *const vi = EROFS_V(inode); struct erofs_sb_info *const sbi = EROFS_I_SB(inode); switch (handler->flags) { @@ -442,9 +460,6 @@ static int erofs_xattr_generic_get(const struct xattr_handler *handler, return -EINVAL; } - if (!vi->xattr_isize) - return -ENOATTR; - return erofs_getxattr(inode, handler->flags, name, buffer, size); } -- cgit v1.2.3 From 609398266c5426db2622dc43db2c95855d3b8e6c Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Mon, 14 Jan 2019 19:40:24 +0800 Subject: staging: erofs: remove unneeded inode_operations Currently, EROFS uses generic iops when xattr is off, it seems unnecessary and a lot of extra code is there. Let's follow what other filesystems do instead. Reviewed-by: Chao Yu Signed-off-by: Gao Xiang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/inode.c | 38 ++++++++++++------------------------ drivers/staging/erofs/internal.h | 42 +++++++++++++++++----------------------- drivers/staging/erofs/namei.c | 4 ---- drivers/staging/erofs/xattr.h | 4 ---- 4 files changed, 30 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/inode.c b/drivers/staging/erofs/inode.c index f99954dbfdb5..4f04f7c38cf2 100644 --- a/drivers/staging/erofs/inode.c +++ b/drivers/staging/erofs/inode.c @@ -184,32 +184,18 @@ static int fill_inode(struct inode *inode, int isdir) if (!err) { /* setup the new inode */ if (S_ISREG(inode->i_mode)) { -#ifdef CONFIG_EROFS_FS_XATTR - inode->i_op = &erofs_generic_xattr_iops; -#endif + inode->i_op = &erofs_generic_iops; inode->i_fop = &generic_ro_fops; } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = -#ifdef CONFIG_EROFS_FS_XATTR - &erofs_dir_xattr_iops; -#else - &erofs_dir_iops; -#endif + inode->i_op = &erofs_dir_iops; inode->i_fop = &erofs_dir_fops; } else if (S_ISLNK(inode->i_mode)) { /* by default, page_get_link is used for symlink */ - inode->i_op = -#ifdef CONFIG_EROFS_FS_XATTR - &erofs_symlink_xattr_iops, -#else - &page_symlink_inode_operations; -#endif + inode->i_op = &erofs_symlink_iops; inode_nohighmem(inode); } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { -#ifdef CONFIG_EROFS_FS_XATTR - inode->i_op = &erofs_special_inode_operations; -#endif + inode->i_op = &erofs_generic_iops; init_special_inode(inode, inode->i_mode, inode->i_rdev); } else { err = -EIO; @@ -297,23 +283,23 @@ struct inode *erofs_iget(struct super_block *sb, return inode; } +const struct inode_operations erofs_generic_iops = { #ifdef CONFIG_EROFS_FS_XATTR -const struct inode_operations erofs_generic_xattr_iops = { .listxattr = erofs_listxattr, +#endif }; -const struct inode_operations erofs_symlink_xattr_iops = { +const struct inode_operations erofs_symlink_iops = { .get_link = page_get_link, +#ifdef CONFIG_EROFS_FS_XATTR .listxattr = erofs_listxattr, +#endif }; -const struct inode_operations erofs_special_inode_operations = { - .listxattr = erofs_listxattr, -}; - -const struct inode_operations erofs_fast_symlink_xattr_iops = { +const struct inode_operations erofs_fast_symlink_iops = { .get_link = simple_get_link, +#ifdef CONFIG_EROFS_FS_XATTR .listxattr = erofs_listxattr, -}; #endif +}; diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index 192f4028d85d..ae4f2555f497 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -414,8 +414,6 @@ static inline bool is_inode_layout_inline(struct inode *inode) } extern const struct super_operations erofs_sops; -extern const struct inode_operations erofs_dir_iops; -extern const struct file_operations erofs_dir_fops; extern const struct address_space_operations erofs_raw_access_aops; #ifdef CONFIG_EROFS_FS_ZIP @@ -559,37 +557,33 @@ static inline unsigned long erofs_inode_hash(erofs_nid_t nid) extern struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool dir); -/* dir.c */ -int erofs_namei(struct inode *dir, struct qstr *name, - erofs_nid_t *nid, unsigned *d_type); - -#ifdef CONFIG_EROFS_FS_XATTR -/* xattr.c */ -extern const struct xattr_handler *erofs_xattr_handlers[]; - -/* symlink and special inode */ -extern const struct inode_operations erofs_symlink_xattr_iops; -extern const struct inode_operations erofs_fast_symlink_xattr_iops; -extern const struct inode_operations erofs_special_inode_operations; -#endif +extern const struct inode_operations erofs_generic_iops; +extern const struct inode_operations erofs_symlink_iops; +extern const struct inode_operations erofs_fast_symlink_iops; static inline void set_inode_fast_symlink(struct inode *inode) { -#ifdef CONFIG_EROFS_FS_XATTR - inode->i_op = &erofs_fast_symlink_xattr_iops; -#else - inode->i_op = &simple_symlink_inode_operations; -#endif + inode->i_op = &erofs_fast_symlink_iops; } static inline bool is_inode_fast_symlink(struct inode *inode) { + return inode->i_op == &erofs_fast_symlink_iops; +} + +/* namei.c */ +extern const struct inode_operations erofs_dir_iops; + +int erofs_namei(struct inode *dir, struct qstr *name, + erofs_nid_t *nid, unsigned int *d_type); + +/* dir.c */ +extern const struct file_operations erofs_dir_fops; + #ifdef CONFIG_EROFS_FS_XATTR - return inode->i_op == &erofs_fast_symlink_xattr_iops; -#else - return inode->i_op == &simple_symlink_inode_operations; +/* xattr.c */ +extern const struct xattr_handler *erofs_xattr_handlers[]; #endif -} static inline void *erofs_vmap(struct page **pages, unsigned int count) { diff --git a/drivers/staging/erofs/namei.c b/drivers/staging/erofs/namei.c index 5596c52e246d..7fed1f996ab0 100644 --- a/drivers/staging/erofs/namei.c +++ b/drivers/staging/erofs/namei.c @@ -235,10 +235,6 @@ static struct dentry *erofs_lookup(struct inode *dir, const struct inode_operations erofs_dir_iops = { .lookup = erofs_lookup, -}; - -const struct inode_operations erofs_dir_xattr_iops = { - .lookup = erofs_lookup, #ifdef CONFIG_EROFS_FS_XATTR .listxattr = erofs_listxattr, #endif diff --git a/drivers/staging/erofs/xattr.h b/drivers/staging/erofs/xattr.h index 0c7379282fc5..810fc947701d 100644 --- a/drivers/staging/erofs/xattr.h +++ b/drivers/staging/erofs/xattr.h @@ -68,10 +68,6 @@ static const struct xattr_handler *xattr_handler_map[] = { } #ifdef CONFIG_EROFS_FS_XATTR - -extern const struct inode_operations erofs_generic_xattr_iops; -extern const struct inode_operations erofs_dir_xattr_iops; - int erofs_getxattr(struct inode *, int, const char *, void *, size_t); ssize_t erofs_listxattr(struct dentry *, char *, size_t); #else -- cgit v1.2.3 From 6af7b4830569a125e65a1123a3ac1db44e999929 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Mon, 14 Jan 2019 19:40:25 +0800 Subject: staging: erofs: move erofs_xattr_handlers to xattr.h Let's move independent xattr-related stuffs to xattr.h. No logic changes. Reviewed-by: Chao Yu Signed-off-by: Gao Xiang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/internal.h | 5 ----- drivers/staging/erofs/super.c | 1 + drivers/staging/erofs/xattr.h | 2 ++ 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index ae4f2555f497..99b50b981335 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -580,11 +580,6 @@ int erofs_namei(struct inode *dir, struct qstr *name, /* dir.c */ extern const struct file_operations erofs_dir_fops; -#ifdef CONFIG_EROFS_FS_XATTR -/* xattr.c */ -extern const struct xattr_handler *erofs_xattr_handlers[]; -#endif - static inline void *erofs_vmap(struct page **pages, unsigned int count) { #ifdef CONFIG_EROFS_FS_USE_VM_MAP_RAM diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c index 1c2eb69682ef..45c7f6ddb9f5 100644 --- a/drivers/staging/erofs/super.c +++ b/drivers/staging/erofs/super.c @@ -16,6 +16,7 @@ #include #include #include "internal.h" +#include "xattr.h" #define CREATE_TRACE_POINTS #include diff --git a/drivers/staging/erofs/xattr.h b/drivers/staging/erofs/xattr.h index 810fc947701d..634dae9aaa0b 100644 --- a/drivers/staging/erofs/xattr.h +++ b/drivers/staging/erofs/xattr.h @@ -68,6 +68,8 @@ static const struct xattr_handler *xattr_handler_map[] = { } #ifdef CONFIG_EROFS_FS_XATTR +extern const struct xattr_handler *erofs_xattr_handlers[]; + int erofs_getxattr(struct inode *, int, const char *, void *, size_t); ssize_t erofs_listxattr(struct dentry *, char *, size_t); #else -- cgit v1.2.3 From 3b423417d0d1d5abd46dfc7c3df9977bcb89f3c0 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 15 Jan 2019 09:42:21 +0800 Subject: staging: erofs: clean up erofs_map_blocks_iter This patch cleans up erofs_map_blocks* function and structure family, just simply the code, no logic change. Reviewed-by: Gao Xiang Signed-off-by: Chao Yu Signed-off-by: Gao Xiang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/data.c | 31 +++++-------------------------- drivers/staging/erofs/internal.h | 28 +++++++++++++++------------- drivers/staging/erofs/unzip_vle.c | 30 +++++++++++++++--------------- 3 files changed, 35 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/data.c b/drivers/staging/erofs/data.c index 329fa4fa3e9c..9c471f08ffd4 100644 --- a/drivers/staging/erofs/data.c +++ b/drivers/staging/erofs/data.c @@ -165,37 +165,16 @@ err_out: return err; } -int erofs_map_blocks_iter(struct inode *inode, - struct erofs_map_blocks *map, - struct page **mpage_ret, int flags) -{ - /* by default, reading raw data never use erofs_map_blocks_iter */ - if (unlikely(!is_inode_layout_compression(inode))) { - if (*mpage_ret) - put_page(*mpage_ret); - *mpage_ret = NULL; - - return erofs_map_blocks(inode, map, flags); - } - -#ifdef CONFIG_EROFS_FS_ZIP - return z_erofs_map_blocks_iter(inode, map, mpage_ret, flags); -#else - /* data compression is not available */ - return -ENOTSUPP; -#endif -} - int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map, int flags) { if (unlikely(is_inode_layout_compression(inode))) { - struct page *mpage = NULL; - int err; + int err = z_erofs_map_blocks_iter(inode, map, flags); - err = erofs_map_blocks_iter(inode, map, &mpage, flags); - if (mpage) - put_page(mpage); + if (map->mpage) { + put_page(map->mpage); + map->mpage = NULL; + } return err; } return erofs_map_blocks_flatmode(inode, map, flags); diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index 99b50b981335..c3de24e7fb67 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -461,11 +461,26 @@ struct erofs_map_blocks { u64 m_plen, m_llen; unsigned int m_flags; + + struct page *mpage; }; /* Flags used by erofs_map_blocks() */ #define EROFS_GET_BLOCKS_RAW 0x0001 +#ifdef CONFIG_EROFS_FS_ZIP +int z_erofs_map_blocks_iter(struct inode *inode, + struct erofs_map_blocks *map, + int flags); +#else +static inline int z_erofs_map_blocks_iter(struct inode *inode, + struct erofs_map_blocks *map, + int flags) +{ + return -ENOTSUPP; +} +#endif + /* data.c */ static inline struct bio * erofs_grab_bio(struct super_block *sb, @@ -522,19 +537,6 @@ static inline struct page *erofs_get_meta_page_nofail(struct super_block *sb, } extern int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int); -extern int erofs_map_blocks_iter(struct inode *, struct erofs_map_blocks *, - struct page **, int); - -struct erofs_map_blocks_iter { - struct erofs_map_blocks map; - struct page *mpage; -}; - -#ifdef CONFIG_EROFS_FS_ZIP -extern int z_erofs_map_blocks_iter(struct inode *, - struct erofs_map_blocks *, - struct page **, int); -#endif static inline struct page * erofs_get_inline_page(struct inode *inode, diff --git a/drivers/staging/erofs/unzip_vle.c b/drivers/staging/erofs/unzip_vle.c index 584612b47369..29b3b1dc67f1 100644 --- a/drivers/staging/erofs/unzip_vle.c +++ b/drivers/staging/erofs/unzip_vle.c @@ -636,7 +636,7 @@ struct z_erofs_vle_frontend { struct inode *const inode; struct z_erofs_vle_work_builder builder; - struct erofs_map_blocks_iter m_iter; + struct erofs_map_blocks map; z_erofs_vle_owned_workgrp_t owned_head; @@ -647,8 +647,9 @@ struct z_erofs_vle_frontend { #define VLE_FRONTEND_INIT(__i) { \ .inode = __i, \ - .m_iter = { \ - { .m_llen = 0, .m_plen = 0 }, \ + .map = { \ + .m_llen = 0, \ + .m_plen = 0, \ .mpage = NULL \ }, \ .builder = VLE_WORK_BUILDER_INIT(), \ @@ -681,8 +682,7 @@ static int z_erofs_do_read_page(struct z_erofs_vle_frontend *fe, { struct super_block *const sb = fe->inode->i_sb; struct erofs_sb_info *const sbi __maybe_unused = EROFS_SB(sb); - struct erofs_map_blocks_iter *const m = &fe->m_iter; - struct erofs_map_blocks *const map = &m->map; + struct erofs_map_blocks *const map = &fe->map; struct z_erofs_vle_work_builder *const builder = &fe->builder; const loff_t offset = page_offset(page); @@ -715,7 +715,7 @@ repeat: map->m_la = offset + cur; map->m_llen = 0; - err = erofs_map_blocks_iter(fe->inode, map, &m->mpage, 0); + err = z_erofs_map_blocks_iter(fe->inode, map, 0); if (unlikely(err)) goto err_out; @@ -1484,8 +1484,8 @@ static int z_erofs_vle_normalaccess_readpage(struct file *file, z_erofs_submit_and_unzip(&f, &pagepool, true); out: - if (f.m_iter.mpage) - put_page(f.m_iter.mpage); + if (f.map.mpage) + put_page(f.map.mpage); /* clean up the remaining free pages */ put_pages_list(&pagepool); @@ -1555,8 +1555,8 @@ static int z_erofs_vle_normalaccess_readpages(struct file *filp, z_erofs_submit_and_unzip(&f, &pagepool, sync); - if (f.m_iter.mpage) - put_page(f.m_iter.mpage); + if (f.map.mpage) + put_page(f.map.mpage); /* clean up the remaining free pages */ put_pages_list(&pagepool); @@ -1701,14 +1701,14 @@ vle_get_logical_extent_head(const struct vle_map_blocks_iter_ctx *ctx, int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map, - struct page **mpage_ret, int flags) + int flags) { void *kaddr; const struct vle_map_blocks_iter_ctx ctx = { .inode = inode, .sb = inode->i_sb, .clusterbits = EROFS_I_SB(inode)->clusterbits, - .mpage_ret = mpage_ret, + .mpage_ret = &map->mpage, .kaddr_ret = &kaddr }; const unsigned int clustersize = 1 << ctx.clusterbits; @@ -1722,7 +1722,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, /* initialize `pblk' to keep gcc from printing foolish warnings */ erofs_blk_t mblk, pblk = 0; - struct page *mpage = *mpage_ret; + struct page *mpage = map->mpage; struct z_erofs_vle_decompressed_index *di; unsigned int cluster_type, logical_cluster_ofs; int err = 0; @@ -1758,7 +1758,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, err = PTR_ERR(mpage); goto out; } - *mpage_ret = mpage; + map->mpage = mpage; } else { lock_page(mpage); DBG_BUGON(!PageUptodate(mpage)); @@ -1818,7 +1818,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, /* get the correspoinding first chunk */ err = vle_get_logical_extent_head(&ctx, lcn, &ofs, &pblk, &map->m_flags); - mpage = *mpage_ret; + mpage = map->mpage; if (unlikely(err)) { if (mpage) -- cgit v1.2.3 From e6718f686ed4b9e48c26bf3cda220a2c98df20e3 Mon Sep 17 00:00:00 2001 From: Brajeswar Ghosh Date: Wed, 9 Jan 2019 20:55:59 +0530 Subject: staging/android/vsoc: Remove duplicate header Remove linux/mutex.h which is included more than once Signed-off-by: Brajeswar Ghosh Acked-by: Souptick Joarder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/vsoc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c index 22571abcaa4e..8a75bd27c413 100644 --- a/drivers/staging/android/vsoc.c +++ b/drivers/staging/android/vsoc.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "uapi/vsoc_shm.h" -- cgit v1.2.3 From 891fd847605d4d7e8aef07db39f1868b5a70e047 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 14 Jan 2019 22:40:58 -0600 Subject: staging: rtl8188eu: Replace kzalloc with kcalloc Replace kzalloc() function with its 2-factor argument form, kcalloc(). This patch replaces cases of: kzalloc(a * b, gfp) with: kcalloc(a, b, gfp) This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_efuse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c index b7be71f904ed..51c3dd6d7ffb 100644 --- a/drivers/staging/rtl8188eu/core/rtw_efuse.c +++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c @@ -88,7 +88,9 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf) if (!efuseTbl) return; - tmp = kzalloc(EFUSE_MAX_SECTION_88E * (sizeof(void *) + EFUSE_MAX_WORD_UNIT * sizeof(u16)), GFP_KERNEL); + tmp = kcalloc(EFUSE_MAX_SECTION_88E, + sizeof(void *) + EFUSE_MAX_WORD_UNIT * sizeof(u16), + GFP_KERNEL); if (!tmp) { DBG_88E("%s: alloc eFuseWord fail!\n", __func__); goto eFuseWord_failed; -- cgit v1.2.3 From 47ed91d3a26825cf276c490b1e4f7588111370d4 Mon Sep 17 00:00:00 2001 From: Alexander Schroth Date: Thu, 10 Jan 2019 15:57:22 +0100 Subject: staging: comedi: ni_pcidio: make defines uppercase According to the Linux coding guidelines, defines should be written in uppercase. This patch converts all define-statements in the ni_pcidio.c file to uppercase, thus matching the coding style of the kernel. Signed-off-by: Alexander Schroth Signed-off-by: Marco Ammon Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_pcidio.c | 444 +++++++++++++++-------------- 1 file changed, 223 insertions(+), 221 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index b9a0dc6eac44..4bdef87d5dd7 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -49,116 +49,117 @@ /* defines for the PCI-DIO-32HS */ -#define Window_Address 4 /* W */ -#define Interrupt_And_Window_Status 4 /* R */ -#define IntStatus1 BIT(0) -#define IntStatus2 BIT(1) -#define WindowAddressStatus_mask 0x7c - -#define Master_DMA_And_Interrupt_Control 5 /* W */ -#define InterruptLine(x) ((x) & 3) -#define OpenInt BIT(2) -#define Group_Status 5 /* R */ -#define DataLeft BIT(0) -#define Req BIT(2) -#define StopTrig BIT(3) - -#define Group_1_Flags 6 /* R */ -#define Group_2_Flags 7 /* R */ -#define TransferReady BIT(0) -#define CountExpired BIT(1) -#define Waited BIT(5) -#define PrimaryTC BIT(6) -#define SecondaryTC BIT(7) +#define WINDOW_ADDRESS 4 /* W */ +#define INTERRUPT_AND_WINDOW_STATUS 4 /* R */ +#define INT_STATUS_1 BIT(0) +#define INT_STATUS_2 BIT(1) +#define WINDOW_ADDRESS_STATUS_MASK 0x7c + +#define MASTER_DMA_AND_INTERRUPT_CONTROL 5 /* W */ +#define INTERRUPT_LINE(x) ((x) & 3) +#define OPEN_INT BIT(2) +#define GROUP_STATUS 5 /* R */ +#define DATA_LEFT BIT(0) +#define REQ BIT(2) +#define STOP_TRIG BIT(3) + +#define GROUP_1_FLAGS 6 /* R */ +#define GROUP_2_FLAGS 7 /* R */ +#define TRANSFER_READY BIT(0) +#define COUNT_EXPIRED BIT(1) +#define WAITED BIT(5) +#define PRIMARY_TC BIT(6) +#define SECONDARY_TC BIT(7) /* #define SerialRose */ /* #define ReqRose */ /* #define Paused */ -#define Group_1_First_Clear 6 /* W */ -#define Group_2_First_Clear 7 /* W */ -#define ClearWaited BIT(3) -#define ClearPrimaryTC BIT(4) -#define ClearSecondaryTC BIT(5) -#define DMAReset BIT(6) -#define FIFOReset BIT(7) -#define ClearAll 0xf8 - -#define Group_1_FIFO 8 /* W */ -#define Group_2_FIFO 12 /* W */ - -#define Transfer_Count 20 -#define Chip_ID_D 24 -#define Chip_ID_I 25 -#define Chip_ID_O 26 -#define Chip_Version 27 -#define Port_IO(x) (28 + (x)) -#define Port_Pin_Directions(x) (32 + (x)) -#define Port_Pin_Mask(x) (36 + (x)) -#define Port_Pin_Polarities(x) (40 + (x)) - -#define Master_Clock_Routing 45 -#define RTSIClocking(x) (((x) & 3) << 4) - -#define Group_1_Second_Clear 46 /* W */ -#define Group_2_Second_Clear 47 /* W */ -#define ClearExpired BIT(0) - -#define Port_Pattern(x) (48 + (x)) - -#define Data_Path 64 -#define FIFOEnableA BIT(0) -#define FIFOEnableB BIT(1) -#define FIFOEnableC BIT(2) -#define FIFOEnableD BIT(3) -#define Funneling(x) (((x) & 3) << 4) -#define GroupDirection BIT(7) - -#define Protocol_Register_1 65 -#define OpMode Protocol_Register_1 -#define RunMode(x) ((x) & 7) -#define Numbered BIT(3) - -#define Protocol_Register_2 66 -#define ClockReg Protocol_Register_2 -#define ClockLine(x) (((x) & 3) << 5) -#define InvertStopTrig BIT(7) -#define DataLatching(x) (((x) & 3) << 5) - -#define Protocol_Register_3 67 -#define Sequence Protocol_Register_3 - -#define Protocol_Register_14 68 /* 16 bit */ -#define ClockSpeed Protocol_Register_14 - -#define Protocol_Register_4 70 -#define ReqReg Protocol_Register_4 -#define ReqConditioning(x) (((x) & 7) << 3) - -#define Protocol_Register_5 71 -#define BlockMode Protocol_Register_5 +#define GROUP_1_FIRST_CLEAR 6 /* W */ +#define GROUP_2_FIRST_CLEAR 7 /* W */ +#define CLEAR_WAITED BIT(3) +#define CLEAR_PRIMARY_TC BIT(4) +#define CLEAR_SECONDARY_TC BIT(5) +#define DMA_RESET BIT(6) +#define FIFO_RESET BIT(7) +#define CLEAR_ALL 0xf8 + +#define GROUP_1_FIFO 8 /* W */ +#define GROUP_2_FIFO 12 /* W */ + +#define TRANSFER_COUNT 20 +#define CHIP_ID_D 24 +#define CHIP_ID_I 25 +#define CHIP_ID_O 26 +#define CHIP_VERSION 27 +#define PORT_IO(x) (28 + (x)) +#define PORT_PIN_DIRECTIONS(x) (32 + (x)) +#define PORT_PIN_MASK(x) (36 + (x)) +#define PORT_PIN_POLARITIES(x) (40 + (x)) + +#define MASTER_CLOCK_ROUTING 45 +#define RTSI_CLOCKING(x) (((x) & 3) << 4) + +#define GROUP_1_SECOND_CLEAR 46 /* W */ +#define GROUP_2_SECOND_CLEAR 47 /* W */ +#define CLEAR_EXPIRED BIT(0) + +#define PORT_PATTERN(x) (48 + (x)) + +#define DATA_PATH 64 +#define FIFO_ENABLE_A BIT(0) +#define FIFO_ENABLE_B BIT(1) +#define FIFO_ENABLE_C BIT(2) +#define FIFO_ENABLE_D BIT(3) +#define FUNNELING(x) (((x) & 3) << 4) +#define GROUP_DIRECTION BIT(7) + +#define PROTOCOL_REGISTER_1 65 +#define OP_MODE PROTOCOL_REGISTER_1 +#define RUN_MODE(x) ((x) & 7) +#define NUMBERED BIT(3) + +#define PROTOCOL_REGISTER_2 66 +#define CLOCK_REG PROTOCOL_REGISTER_2 +#define CLOCK_LINE(x) (((x) & 3) << 5) +#define INVERT_STOP_TRIG BIT(7) +#define DATA_LATCHING(x) (((x) & 3) << 5) + +#define PROTOCOL_REGISTER_3 67 +#define SEQUENCE PROTOCOL_REGISTER_3 + +#define PROTOCOL_REGISTER_14 68 /* 16 bit */ +#define CLOCK_SPEED PROTOCOL_REGISTER_14 + +#define PROTOCOL_REGISTER_4 70 +#define REQ_REG PROTOCOL_REGISTER_4 +#define REQ_CONDITIONING(x) (((x) & 7) << 3) + +#define PROTOCOL_REGISTER_5 71 +#define BLOCK_MODE PROTOCOL_REGISTER_5 #define FIFO_Control 72 -#define ReadyLevel(x) ((x) & 7) - -#define Protocol_Register_6 73 -#define LinePolarities Protocol_Register_6 -#define InvertAck BIT(0) -#define InvertReq BIT(1) -#define InvertClock BIT(2) -#define InvertSerial BIT(3) -#define OpenAck BIT(4) -#define OpenClock BIT(5) - -#define Protocol_Register_7 74 -#define AckSer Protocol_Register_7 -#define AckLine(x) (((x) & 3) << 2) -#define ExchangePins BIT(7) - -#define Interrupt_Control 75 - /* bits same as flags */ - -#define DMA_Line_Control_Group1 76 -#define DMA_Line_Control_Group2 108 +#define READY_LEVEL(x) ((x) & 7) + +#define PROTOCOL_REGISTER_6 73 +#define LINE_POLARITIES PROTOCOL_REGISTER_6 +#define INVERT_ACK BIT(0) +#define INVERT_REQ BIT(1) +#define INVERT_CLOCK BIT(2) +#define INVERT_SERIAL BIT(3) +#define OPEN_ACK BIT(4) +#define OPEN_CLOCK BIT(5) + +#define PROTOCOL_REGISTER_7 74 +#define ACK_SER PROTOCOL_REGISTER_7 +#define ACK_LINE(x) (((x) & 3) << 2) +#define EXCHANGE_PINS BIT(7) + +#define INTERRUPT_CONTROL 75 +/* bits same as flags */ + +#define DMA_LINE_CONTROL_GROUP1 76 +#define DMA_LINE_CONTROL_GROUP2 108 + /* channel zero is none */ static inline unsigned int primary_DMAChannel_bits(unsigned int channel) { @@ -170,41 +171,41 @@ static inline unsigned int secondary_DMAChannel_bits(unsigned int channel) return (channel << 2) & 0xc; } -#define Transfer_Size_Control 77 -#define TransferWidth(x) ((x) & 3) -#define TransferLength(x) (((x) & 3) << 3) -#define RequireRLevel BIT(5) +#define TRANSFER_SIZE_CONTROL 77 +#define TRANSFER_WIDTH(x) ((x) & 3) +#define TRANSFER_LENGTH(x) (((x) & 3) << 3) +#define REQUIRE_R_LEVEL BIT(5) -#define Protocol_Register_15 79 -#define DAQOptions Protocol_Register_15 -#define StartSource(x) ((x) & 0x3) -#define InvertStart BIT(2) -#define StopSource(x) (((x) & 0x3) << 3) -#define ReqStart BIT(6) -#define PreStart BIT(7) +#define PROTOCOL_REGISTER_15 79 +#define DAQ_OPTIONS PROTOCOL_REGISTER_15 +#define START_SOURCE(x) ((x) & 0x3) +#define INVERT_START BIT(2) +#define STOP_SOURCE(x) (((x) & 0x3) << 3) +#define REQ_START BIT(6) +#define PRE_START BIT(7) -#define Pattern_Detection 81 -#define DetectionMethod BIT(0) -#define InvertMatch BIT(1) -#define IE_Pattern_Detection BIT(2) +#define PATTERN_DETECTION 81 +#define DETECTION_METHOD BIT(0) +#define INVERT_MATCH BIT(1) +#define IE_PATTERN_DETECTION BIT(2) -#define Protocol_Register_9 82 -#define ReqDelay Protocol_Register_9 +#define PROTOCOL_REGISTER_9 82 +#define REQ_DELAY PROTOCOL_REGISTER_9 -#define Protocol_Register_10 83 -#define ReqNotDelay Protocol_Register_10 +#define PROTOCOL_REGISTER_10 83 +#define REQ_NOT_DELAY PROTOCOL_REGISTER_10 -#define Protocol_Register_11 84 -#define AckDelay Protocol_Register_11 +#define PROTOCOL_REGISTER_11 84 +#define ACK_DELAY PROTOCOL_REGISTER_11 -#define Protocol_Register_12 85 -#define AckNotDelay Protocol_Register_12 +#define PROTOCOL_REGISTER_12 85 +#define ACK_NOT_DELAY PROTOCOL_REGISTER_12 -#define Protocol_Register_13 86 -#define Data1Delay Protocol_Register_13 +#define PROTOCOL_REGISTER_13 86 +#define DATA_1_DELAY PROTOCOL_REGISTER_13 -#define Protocol_Register_8 88 /* 32 bit */ -#define StartDelay Protocol_Register_8 +#define PROTOCOL_REGISTER_8 88 /* 32 bit */ +#define START_DELAY PROTOCOL_REGISTER_8 /* Firmware files for PCI-6524 */ #define FW_PCI_6534_MAIN "ni6534a.bin" @@ -246,9 +247,10 @@ enum FPGA_Control_Bits { #define TIMER_BASE 50 /* nanoseconds */ #ifdef USE_DMA -#define IntEn (CountExpired | Waited | PrimaryTC | SecondaryTC) +#define INT_EN (COUNT_EXPIRED | WAITED | PRIMARY_TC | SECONDARY_TC) #else -#define IntEn (TransferReady | CountExpired | Waited | PrimaryTC | SecondaryTC) +#define INT_EN (TRANSFER_READY | COUNT_EXPIRED | WAITED \ + | PRIMARY_TC | SECONDARY_TC) #endif enum nidio_boardid { @@ -283,7 +285,7 @@ struct nidio96_private { struct mite *mite; int boardtype; int dio; - unsigned short OpModeBits; + unsigned short OP_MODEBits; struct mite_channel *di_mite_chan; struct mite_ring *di_mite_ring; spinlock_t mite_channel_lock; @@ -307,7 +309,7 @@ static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev) devpriv->di_mite_chan->dir = COMEDI_INPUT; writeb(primary_DMAChannel_bits(devpriv->di_mite_chan->channel) | secondary_DMAChannel_bits(devpriv->di_mite_chan->channel), - dev->mmio + DMA_Line_Control_Group1); + dev->mmio + DMA_LINE_CONTROL_GROUP1); mmiowb(); spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return 0; @@ -324,7 +326,7 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) devpriv->di_mite_chan = NULL; writeb(primary_DMAChannel_bits(0) | secondary_DMAChannel_bits(0), - dev->mmio + DMA_Line_Control_Group1); + dev->mmio + DMA_LINE_CONTROL_GROUP1); mmiowb(); } spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); @@ -391,8 +393,8 @@ static irqreturn_t nidio_interrupt(int irq, void *d) /* Lock to avoid race with comedi_poll */ spin_lock(&dev->spinlock); - status = readb(dev->mmio + Interrupt_And_Window_Status); - flags = readb(dev->mmio + Group_1_Flags); + status = readb(dev->mmio + INTERRUPT_AND_WINDOW_STATUS); + flags = readb(dev->mmio + GROUP_1_FLAGS); spin_lock(&devpriv->mite_channel_lock); if (devpriv->di_mite_chan) { @@ -401,63 +403,63 @@ static irqreturn_t nidio_interrupt(int irq, void *d) } spin_unlock(&devpriv->mite_channel_lock); - while (status & DataLeft) { + while (status & DATA_LEFT) { work++; if (work > 20) { dev_dbg(dev->class_dev, "too much work in interrupt\n"); writeb(0x00, - dev->mmio + Master_DMA_And_Interrupt_Control); + dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL); break; } - flags &= IntEn; + flags &= INT_EN; - if (flags & TransferReady) { - while (flags & TransferReady) { + if (flags & TRANSFER_READY) { + while (flags & TRANSFER_READY) { work++; if (work > 100) { dev_dbg(dev->class_dev, "too much work in interrupt\n"); writeb(0x00, dev->mmio + - Master_DMA_And_Interrupt_Control + MASTER_DMA_AND_INTERRUPT_CONTROL ); goto out; } - auxdata = readl(dev->mmio + Group_1_FIFO); + auxdata = readl(dev->mmio + GROUP_1_FIFO); comedi_buf_write_samples(s, &auxdata, 1); - flags = readb(dev->mmio + Group_1_Flags); + flags = readb(dev->mmio + GROUP_1_FLAGS); } } - if (flags & CountExpired) { - writeb(ClearExpired, dev->mmio + Group_1_Second_Clear); + if (flags & COUNT_EXPIRED) { + writeb(CLEAR_EXPIRED, dev->mmio + GROUP_1_SECOND_CLEAR); async->events |= COMEDI_CB_EOA; - writeb(0x00, dev->mmio + OpMode); + writeb(0x00, dev->mmio + OP_MODE); break; - } else if (flags & Waited) { - writeb(ClearWaited, dev->mmio + Group_1_First_Clear); + } else if (flags & WAITED) { + writeb(CLEAR_WAITED, dev->mmio + GROUP_1_FIRST_CLEAR); async->events |= COMEDI_CB_ERROR; break; - } else if (flags & PrimaryTC) { - writeb(ClearPrimaryTC, - dev->mmio + Group_1_First_Clear); + } else if (flags & PRIMARY_TC) { + writeb(CLEAR_PRIMARY_TC, + dev->mmio + GROUP_1_FIRST_CLEAR); async->events |= COMEDI_CB_EOA; - } else if (flags & SecondaryTC) { - writeb(ClearSecondaryTC, - dev->mmio + Group_1_First_Clear); + } else if (flags & SECONDARY_TC) { + writeb(CLEAR_SECONDARY_TC, + dev->mmio + GROUP_1_FIRST_CLEAR); async->events |= COMEDI_CB_EOA; } - flags = readb(dev->mmio + Group_1_Flags); - status = readb(dev->mmio + Interrupt_And_Window_Status); + flags = readb(dev->mmio + GROUP_1_FLAGS); + status = readb(dev->mmio + INTERRUPT_AND_WINDOW_STATUS); } out: comedi_handle_events(dev, s); #if 0 if (!tag) - writeb(0x03, dev->mmio + Master_DMA_And_Interrupt_Control); + writeb(0x03, dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL); #endif spin_unlock(&dev->spinlock); @@ -484,7 +486,7 @@ static int ni_pcidio_insn_config(struct comedi_device *dev, if (ret) return ret; - writel(s->io_bits, dev->mmio + Port_Pin_Directions(0)); + writel(s->io_bits, dev->mmio + PORT_PIN_DIRECTIONS(0)); return insn->n; } @@ -495,9 +497,9 @@ static int ni_pcidio_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - writel(s->state, dev->mmio + Port_IO(0)); + writel(s->state, dev->mmio + PORT_IO(0)); - data[1] = readl(dev->mmio + Port_IO(0)); + data[1] = readl(dev->mmio + PORT_IO(0)); return insn->n; } @@ -609,7 +611,7 @@ static int ni_pcidio_inttrig(struct comedi_device *dev, if (trig_num != cmd->start_arg) return -EINVAL; - writeb(devpriv->OpModeBits, dev->mmio + OpMode); + writeb(devpriv->OP_MODEBits, dev->mmio + OP_MODE); s->async->inttrig = NULL; return 1; @@ -621,78 +623,78 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct comedi_cmd *cmd = &s->async->cmd; /* XXX configure ports for input */ - writel(0x0000, dev->mmio + Port_Pin_Directions(0)); + writel(0x0000, dev->mmio + PORT_PIN_DIRECTIONS(0)); if (1) { /* enable fifos A B C D */ - writeb(0x0f, dev->mmio + Data_Path); + writeb(0x0f, dev->mmio + DATA_PATH); /* set transfer width a 32 bits */ - writeb(TransferWidth(0) | TransferLength(0), - dev->mmio + Transfer_Size_Control); + writeb(TRANSFER_WIDTH(0) | TRANSFER_LENGTH(0), + dev->mmio + TRANSFER_SIZE_CONTROL); } else { - writeb(0x03, dev->mmio + Data_Path); - writeb(TransferWidth(3) | TransferLength(0), - dev->mmio + Transfer_Size_Control); + writeb(0x03, dev->mmio + DATA_PATH); + writeb(TRANSFER_WIDTH(3) | TRANSFER_LENGTH(0), + dev->mmio + TRANSFER_SIZE_CONTROL); } /* protocol configuration */ if (cmd->scan_begin_src == TRIG_TIMER) { /* page 4-5, "input with internal REQs" */ - writeb(0, dev->mmio + OpMode); - writeb(0x00, dev->mmio + ClockReg); - writeb(1, dev->mmio + Sequence); - writeb(0x04, dev->mmio + ReqReg); - writeb(4, dev->mmio + BlockMode); - writeb(3, dev->mmio + LinePolarities); - writeb(0xc0, dev->mmio + AckSer); + writeb(0, dev->mmio + OP_MODE); + writeb(0x00, dev->mmio + CLOCK_REG); + writeb(1, dev->mmio + SEQUENCE); + writeb(0x04, dev->mmio + REQ_REG); + writeb(4, dev->mmio + BLOCK_MODE); + writeb(3, dev->mmio + LINE_POLARITIES); + writeb(0xc0, dev->mmio + ACK_SER); writel(ni_pcidio_ns_to_timer(&cmd->scan_begin_arg, CMDF_ROUND_NEAREST), - dev->mmio + StartDelay); - writeb(1, dev->mmio + ReqDelay); - writeb(1, dev->mmio + ReqNotDelay); - writeb(1, dev->mmio + AckDelay); - writeb(0x0b, dev->mmio + AckNotDelay); - writeb(0x01, dev->mmio + Data1Delay); + dev->mmio + START_DELAY); + writeb(1, dev->mmio + REQ_DELAY); + writeb(1, dev->mmio + REQ_NOT_DELAY); + writeb(1, dev->mmio + ACK_DELAY); + writeb(0x0b, dev->mmio + ACK_NOT_DELAY); + writeb(0x01, dev->mmio + DATA_1_DELAY); /* * manual, page 4-5: - * ClockSpeed comment is incorrectly listed on DAQOptions + * CLOCK_SPEED comment is incorrectly listed on DAQ_OPTIONS */ - writew(0, dev->mmio + ClockSpeed); - writeb(0, dev->mmio + DAQOptions); + writew(0, dev->mmio + CLOCK_SPEED); + writeb(0, dev->mmio + DAQ_OPTIONS); } else { /* TRIG_EXT */ /* page 4-5, "input with external REQs" */ - writeb(0, dev->mmio + OpMode); - writeb(0x00, dev->mmio + ClockReg); - writeb(0, dev->mmio + Sequence); - writeb(0x00, dev->mmio + ReqReg); - writeb(4, dev->mmio + BlockMode); + writeb(0, dev->mmio + OP_MODE); + writeb(0x00, dev->mmio + CLOCK_REG); + writeb(0, dev->mmio + SEQUENCE); + writeb(0x00, dev->mmio + REQ_REG); + writeb(4, dev->mmio + BLOCK_MODE); if (!(cmd->scan_begin_arg & CR_INVERT)) /* Leading Edge */ - writeb(0, dev->mmio + LinePolarities); + writeb(0, dev->mmio + LINE_POLARITIES); else /* Trailing Edge */ - writeb(2, dev->mmio + LinePolarities); - writeb(0x00, dev->mmio + AckSer); - writel(1, dev->mmio + StartDelay); - writeb(1, dev->mmio + ReqDelay); - writeb(1, dev->mmio + ReqNotDelay); - writeb(1, dev->mmio + AckDelay); - writeb(0x0C, dev->mmio + AckNotDelay); - writeb(0x10, dev->mmio + Data1Delay); - writew(0, dev->mmio + ClockSpeed); - writeb(0x60, dev->mmio + DAQOptions); + writeb(2, dev->mmio + LINE_POLARITIES); + writeb(0x00, dev->mmio + ACK_SER); + writel(1, dev->mmio + START_DELAY); + writeb(1, dev->mmio + REQ_DELAY); + writeb(1, dev->mmio + REQ_NOT_DELAY); + writeb(1, dev->mmio + ACK_DELAY); + writeb(0x0C, dev->mmio + ACK_NOT_DELAY); + writeb(0x10, dev->mmio + DATA_1_DELAY); + writew(0, dev->mmio + CLOCK_SPEED); + writeb(0x60, dev->mmio + DAQ_OPTIONS); } if (cmd->stop_src == TRIG_COUNT) { writel(cmd->stop_arg, - dev->mmio + Transfer_Count); + dev->mmio + TRANSFER_COUNT); } else { /* XXX */ } #ifdef USE_DMA - writeb(ClearPrimaryTC | ClearSecondaryTC, - dev->mmio + Group_1_First_Clear); + writeb(CLEAR_PRIMARY_TC | CLEAR_SECONDARY_TC, + dev->mmio + GROUP_1_FIRST_CLEAR); { int retval = setup_mite_dma(dev, s); @@ -701,25 +703,25 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return retval; } #else - writeb(0x00, dev->mmio + DMA_Line_Control_Group1); + writeb(0x00, dev->mmio + DMA_LINE_CONTROL_GROUP1); #endif - writeb(0x00, dev->mmio + DMA_Line_Control_Group2); + writeb(0x00, dev->mmio + DMA_LINE_CONTROL_GROUP2); /* clear and enable interrupts */ - writeb(0xff, dev->mmio + Group_1_First_Clear); - /* writeb(ClearExpired, dev->mmio+Group_1_Second_Clear); */ + writeb(0xff, dev->mmio + GROUP_1_FIRST_CLEAR); + /* writeb(CLEAR_EXPIRED, dev->mmio+GROUP_1_SECOND_CLEAR); */ - writeb(IntEn, dev->mmio + Interrupt_Control); - writeb(0x03, dev->mmio + Master_DMA_And_Interrupt_Control); + writeb(INT_EN, dev->mmio + INTERRUPT_CONTROL); + writeb(0x03, dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL); if (cmd->stop_src == TRIG_NONE) { - devpriv->OpModeBits = DataLatching(0) | RunMode(7); + devpriv->OP_MODEBits = DATA_LATCHING(0) | RUN_MODE(7); } else { /* TRIG_TIMER */ - devpriv->OpModeBits = Numbered | RunMode(7); + devpriv->OP_MODEBits = NUMBERED | RUN_MODE(7); } if (cmd->start_src == TRIG_NOW) { /* start */ - writeb(devpriv->OpModeBits, dev->mmio + OpMode); + writeb(devpriv->OP_MODEBits, dev->mmio + OP_MODE); s->async->inttrig = NULL; } else { /* TRIG_INT */ @@ -732,7 +734,7 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int ni_pcidio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - writeb(0x00, dev->mmio + Master_DMA_And_Interrupt_Control); + writeb(0x00, dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL); ni_pcidio_release_di_mite_channel(dev); return 0; @@ -869,12 +871,12 @@ static int pci_6534_upload_firmware(struct comedi_device *dev) static void nidio_reset_board(struct comedi_device *dev) { - writel(0, dev->mmio + Port_IO(0)); - writel(0, dev->mmio + Port_Pin_Directions(0)); - writel(0, dev->mmio + Port_Pin_Mask(0)); + writel(0, dev->mmio + PORT_IO(0)); + writel(0, dev->mmio + PORT_PIN_DIRECTIONS(0)); + writel(0, dev->mmio + PORT_PIN_MASK(0)); /* disable interrupts on board */ - writeb(0, dev->mmio + Master_DMA_And_Interrupt_Control); + writeb(0, dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL); } static int nidio_auto_attach(struct comedi_device *dev, @@ -925,7 +927,7 @@ static int nidio_auto_attach(struct comedi_device *dev, return ret; dev_info(dev->class_dev, "%s rev=%d\n", dev->board_name, - readb(dev->mmio + Chip_Version)); + readb(dev->mmio + CHIP_VERSION)); s = &dev->subdevices[0]; -- cgit v1.2.3 From d2c255be37f46b7d484783b556f280d2da3aecf8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 9 Jan 2019 12:06:41 +0000 Subject: staging: wilc1000: remove set but not used variable 'msa' Fixes gcc '-Wunused-but-set-variable' warning: drivers/staging/wilc1000/host_interface.c: In function 'wilc_parse_network_info': drivers/staging/wilc1000/host_interface.c:748:16: warning: variable 'msa' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 5dae6e7155d3..c05c120fafc7 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -745,7 +745,7 @@ static s32 wilc_parse_network_info(u8 *msg_buffer, { struct network_info *info; struct ieee80211_mgmt *mgt; - u8 *wid_val, *msa, *ies; + u8 *wid_val, *ies; u16 wid_len, rx_len, ies_len; u8 msg_type; size_t offset; @@ -764,7 +764,6 @@ static s32 wilc_parse_network_info(u8 *msg_buffer, info->rssi = wid_val[0]; - msa = &wid_val[1]; mgt = (struct ieee80211_mgmt *)&wid_val[1]; rx_len = wid_len - 1; -- cgit v1.2.3 From d94e038910a8ffd6b219e0ba6359dede951dc27e Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 22 Dec 2018 10:24:53 +0100 Subject: staging: goldfish: remove GPL boiler plate text The SPDX identifier is a legally binding shorthand, which can be used instead of the full boiler plate text. There is a SPDX identifier line in goldfish_audio.c. Remove the GPL boiler plate text to reduce file size. Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/goldfish/goldfish_audio.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/goldfish/goldfish_audio.c b/drivers/staging/goldfish/goldfish_audio.c index d4520490cf6d..24a738238f9f 100644 --- a/drivers/staging/goldfish/goldfish_audio.c +++ b/drivers/staging/goldfish/goldfish_audio.c @@ -4,16 +4,6 @@ * * Copyright (C) 2007 Google, Inc. * Copyright (C) 2012 Intel, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include -- cgit v1.2.3 From 01ad0d0b15a968decb171b9bda8e5e4999d628fa Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 22 Dec 2018 10:46:23 +0100 Subject: staging: gs_fpgaboot: add SPDX identifiers This satisfies a checkpatch warning and is the preferred method for notating the license. The SPDX identifier is a legally binding shorthand, which can be used instead of the full boiler plate text. Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gs_fpgaboot/gs_fpgaboot.c | 12 +----------- drivers/staging/gs_fpgaboot/gs_fpgaboot.h | 12 +----------- drivers/staging/gs_fpgaboot/io.c | 13 +------------ drivers/staging/gs_fpgaboot/io.h | 12 +----------- 4 files changed, 4 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c index fa8b27e091a2..3e154562c64d 100644 --- a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c +++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c @@ -1,14 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0+ #include #include diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.h b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h index 986e841f6b5e..5cf12c14cca4 100644 --- a/drivers/staging/gs_fpgaboot/gs_fpgaboot.h +++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h @@ -1,14 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0+ */ #include diff --git a/drivers/staging/gs_fpgaboot/io.c b/drivers/staging/gs_fpgaboot/io.c index 83a13ca7259a..3d17ca557611 100644 --- a/drivers/staging/gs_fpgaboot/io.c +++ b/drivers/staging/gs_fpgaboot/io.c @@ -1,15 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0+ #include #include diff --git a/drivers/staging/gs_fpgaboot/io.h b/drivers/staging/gs_fpgaboot/io.h index bc5d99cbda8f..9bd86a92e90f 100644 --- a/drivers/staging/gs_fpgaboot/io.h +++ b/drivers/staging/gs_fpgaboot/io.h @@ -1,14 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0+ */ #define GPDIR 0 #define GPCFG 4 /* open drain or not */ -- cgit v1.2.3 From e4abc2488073a1e2764313feac5312622c7f04f9 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 22 Dec 2018 10:46:24 +0100 Subject: staging: gs_fpgaboot: cleanup alignment issue - style Cleanup alignment issue reported by checkpatch. CHECK: Alignment should match open parenthesis Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gs_fpgaboot/io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/gs_fpgaboot/io.c b/drivers/staging/gs_fpgaboot/io.c index 3d17ca557611..80903ec36b76 100644 --- a/drivers/staging/gs_fpgaboot/io.c +++ b/drivers/staging/gs_fpgaboot/io.c @@ -39,8 +39,7 @@ int xl_supported_prog_bus_width(enum wbus bus_bytes) case bus_2byte: break; default: - pr_err("unsupported program bus width %d\n", - bus_bytes); + pr_err("unsupported program bus width %d\n", bus_bytes); return 0; } -- cgit v1.2.3 From 0a54ea9f481f1a2ca5a171e91ddaacb75040f287 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Sat, 22 Dec 2018 16:58:06 -0600 Subject: staging: rtlwifi: rtl8822b: fix a missing check of alloc_skb __netdev_alloc_skb() return NULl when it fails. skb_put() further uses it even when the allocation fails, leading to NULL pointer dereference. The fix inserts a check for the return value of __netdev_alloc_skb(). Signed-off-by: Kangjie Lu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtlwifi/rtl8822be/fw.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/rtlwifi/rtl8822be/fw.c b/drivers/staging/rtlwifi/rtl8822be/fw.c index a40396614814..f061dd1382aa 100644 --- a/drivers/staging/rtlwifi/rtl8822be/fw.c +++ b/drivers/staging/rtlwifi/rtl8822be/fw.c @@ -486,6 +486,8 @@ bool rtl8822b_halmac_cb_write_data_h2c(struct rtl_priv *rtlpriv, u8 *buf, /* without GFP_DMA, pci_map_single() may not work */ skb = __netdev_alloc_skb(NULL, size, GFP_ATOMIC | GFP_DMA); + if (!skb) + return false; memcpy((u8 *)skb_put(skb, size), buf, size); return _rtl8822be_send_bcn_or_cmd_packet(rtlpriv->hw, skb, H2C_QUEUE); -- cgit v1.2.3 From 7c106cbb2ba8c86bedd2868b690aee8965476b3b Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 7 Jan 2019 20:31:43 +0100 Subject: staging: mt7621-pci: use PCI definitions instead of hardcode values Seting up ports to enable PCI_COMMAND_MASTER is using '0x4' as a hardcore value and '0x4' also for PCI_COMMAND register instead of use definitions from linux pci system headers. Replace both. Signed-off-by: Sergio Paracuellos Signed-off-by: Greg Kroah-Hartman --- drivers/staging/mt7621-pci/pci-mt7621.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 8db94fdbdd6d..507b8c68d20b 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -515,8 +515,9 @@ static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie) } for (slot = 0; slot < num_slots_enabled; slot++) { - val = read_config(pcie, slot, 0x4); - write_config(pcie, slot, 0x4, val | 0x4); + val = read_config(pcie, slot, PCI_COMMAND); + val |= PCI_COMMAND_MASTER; + write_config(pcie, slot, PCI_COMMAND, val); /* configure RC FTS number to 250 when it leaves L0s */ val = read_config(pcie, slot, PCIE_FTS_NUM); val &= ~PCIE_FTS_NUM_MASK; -- cgit v1.2.3 From 41be1dc75efb81bf3cfb9838998166ce1104e7f3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Jan 2019 23:11:30 +0000 Subject: staging: rtl8712: clean up various indentation and coding style issues There are several statements that are indented incorrectly so fix these. Also remove unnecessary { } braces and clean up a comment. Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/ieee80211.c | 2 +- drivers/staging/rtl8712/rtl8712_led.c | 6 +++--- drivers/staging/rtl8712/rtl871x_mlme.c | 2 +- drivers/staging/rtl8712/rtl871x_recv.c | 4 ++-- drivers/staging/rtl8712/rtl871x_sta_mgt.c | 2 +- drivers/staging/rtl8712/rtl871x_xmit.c | 8 ++++---- 6 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c index bb4f56a5fb01..2eae11dd6b42 100644 --- a/drivers/staging/rtl8712/ieee80211.c +++ b/drivers/staging/rtl8712/ieee80211.c @@ -408,7 +408,7 @@ int r8712_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) match = true; break; } - cnt += in_ie[cnt + 1] + 2; /* goto next */ + cnt += in_ie[cnt + 1] + 2; /* goto next */ } return match; } diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c index 5b1004b2df47..07fcf9b9b811 100644 --- a/drivers/staging/rtl8712/rtl8712_led.c +++ b/drivers/staging/rtl8712/rtl8712_led.c @@ -939,7 +939,7 @@ static void SwLedControlMode1(struct _adapter *padapter, } if (pLed->bLedLinkBlinkInProgress) { del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; + pLed->bLedLinkBlinkInProgress = false; } if (pLed->bLedBlinkInProgress) { del_timer(&pLed->BlinkTimer); @@ -991,7 +991,7 @@ static void SwLedControlMode1(struct _adapter *padapter, } if (pLed->bLedLinkBlinkInProgress) { del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; + pLed->bLedLinkBlinkInProgress = false; } if (pLed->bLedBlinkInProgress) { del_timer(&pLed->BlinkTimer); @@ -1018,7 +1018,7 @@ static void SwLedControlMode1(struct _adapter *padapter, } if (pLed->bLedLinkBlinkInProgress) { del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; + pLed->bLedLinkBlinkInProgress = false; } if (pLed->bLedBlinkInProgress) { del_timer(&pLed->BlinkTimer); diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 986a1d526918..3f17ef6f7e39 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -259,7 +259,7 @@ int r8712_is_same_ibss(struct _adapter *adapter, struct wlan_network *pnetwork) static int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) { - u16 s_cap, d_cap; + u16 s_cap, d_cap; memcpy((u8 *)&s_cap, r8712_get_capability_from_ie(src->IEs), 2); memcpy((u8 *)&d_cap, r8712_get_capability_from_ie(dst->IEs), 2); diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c index f10896df094b..0271ccf25f25 100644 --- a/drivers/staging/rtl8712/rtl871x_recv.c +++ b/drivers/staging/rtl8712/rtl871x_recv.c @@ -54,7 +54,7 @@ sint _r8712_init_recv_priv(struct recv_priv *precvpriv, sint i; union recv_frame *precvframe; - memset((unsigned char *)precvpriv, 0, sizeof(struct recv_priv)); + memset((unsigned char *)precvpriv, 0, sizeof(struct recv_priv)); spin_lock_init(&precvpriv->lock); _init_queue(&precvpriv->free_recv_queue); _init_queue(&precvpriv->recv_pending_queue); @@ -325,7 +325,7 @@ static sint sta2sta_data_frame(struct _adapter *adapter, */ if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) return _FAIL; - sta_addr = pattrib->bssid; + sta_addr = pattrib->bssid; } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { if (bmcast) { /* For AP mode, if DA == MCAST, then BSSID should diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c index 9648ee15b40e..7c30b9e68e70 100644 --- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c +++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c @@ -25,7 +25,7 @@ static void _init_stainfo(struct sta_info *psta) { memset((u8 *)psta, 0, sizeof(struct sta_info)); - spin_lock_init(&psta->lock); + spin_lock_init(&psta->lock); INIT_LIST_HEAD(&psta->list); INIT_LIST_HEAD(&psta->hash_list); _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c index 5c7dc9c6f76b..7c8857409916 100644 --- a/drivers/staging/rtl8712/rtl871x_xmit.c +++ b/drivers/staging/rtl8712/rtl871x_xmit.c @@ -193,8 +193,8 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, pattrib->ether_type = ntohs(etherhdr.h_proto); -{ - /*If driver xmit ARP packet, driver can set ps mode to initial + /* + * If driver xmit ARP packet, driver can set ps mode to initial * setting. It stands for getting DHCP or fix IP. */ if (pattrib->ether_type == 0x0806) { @@ -206,7 +206,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, padapter->registrypriv.smart_ps); } } -} + memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); pattrib->pctrl = 0; @@ -949,7 +949,7 @@ static void alloc_hwxmits(struct _adapter *padapter) pxmitpriv->vo_txqueue.head = 0; hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; - pxmitpriv->vi_txqueue.head = 0; + pxmitpriv->vi_txqueue.head = 0; hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; pxmitpriv->bk_txqueue.head = 0; -- cgit v1.2.3 From e4441911d9694a177be30eb77adf54d511ae192f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Jan 2019 23:22:49 +0000 Subject: staging: rtl8192e: fix various indentation issues There are several statements that have indentation issues, fix these. Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 8 ++++---- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 6 +++--- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 2 +- drivers/staging/rtl8192e/rtl819x_BAProc.c | 6 +++--- drivers/staging/rtl8192e/rtllib_crypt_tkip.c | 2 +- drivers/staging/rtl8192e/rtllib_rx.c | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 1c6ed5b2a6f9..19bb04b3f097 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -660,9 +660,9 @@ static void _rtl92e_hwconfig(struct net_device *dev) case WIRELESS_MODE_AUTO: case WIRELESS_MODE_N_24G: regBwOpMode = BW_OPMODE_20MHZ; - regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | - RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; - regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | + RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; break; case WIRELESS_MODE_N_5G: regBwOpMode = BW_OPMODE_5G; @@ -961,7 +961,7 @@ static void _rtl92e_net_update(struct net_device *dev) net = &priv->rtllib->current_network; rtl92e_config_rate(dev, &rate_config); priv->dot11CurrentPreambleMode = PREAMBLE_AUTO; - priv->basic_rate = rate_config &= 0x15f; + priv->basic_rate = rate_config &= 0x15f; rtl92e_writew(dev, BSSIDR, *(u16 *)net->bssid); rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(net->bssid + 2)); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 96f265eee007..7031f6833b8b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -436,7 +436,7 @@ static int _rtl92e_qos_handle_probe_response(struct r8192_priv *priv, network->qos_data.param_count)) { network->qos_data.old_param_count = network->qos_data.param_count; - priv->rtllib->wmm_acm = network->qos_data.wmm_acm; + priv->rtllib->wmm_acm = network->qos_data.wmm_acm; schedule_work(&priv->qos_activate); RT_TRACE(COMP_QOS, "QoS parameters change call qos_activate\n"); @@ -1573,7 +1573,7 @@ static void _rtl92e_free_rx_ring(struct net_device *dev) pci_unmap_single(priv->pdev, *((dma_addr_t *)skb->cb), priv->rxbuffersize, PCI_DMA_FROMDEVICE); - kfree_skb(skb); + kfree_skb(skb); } pci_free_consistent(priv->pdev, @@ -2515,7 +2515,7 @@ static int _rtl92e_pci_probe(struct pci_dev *pdev, if (dev_alloc_name(dev, ifname) < 0) { RT_TRACE(COMP_INIT, "Oops: devname already taken! Trying wlan%%d...\n"); - dev_alloc_name(dev, ifname); + dev_alloc_name(dev, ifname); } RT_TRACE(COMP_INIT, "Driver probe completed1\n"); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 9bf95bd0ad13..157bcee34067 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -996,7 +996,7 @@ static void _rtl92e_dm_check_tx_power_tracking_tssi(struct net_device *dev) tx_power_track_counter++; - if (tx_power_track_counter >= 180) { + if (tx_power_track_counter >= 180) { schedule_delayed_work(&priv->txpower_tracking_wq, 0); tx_power_track_counter = 0; } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index b798cde0ce47..44e06cba7b7b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -738,7 +738,7 @@ static int _rtl92e_wx_set_enc(struct net_device *dev, else if (wrqu->encoding.length == 0xd) { ieee->pairwise_key_type = KEY_TYPE_WEP104; - rtl92e_enable_hw_security_config(dev); + rtl92e_enable_hw_security_config(dev); rtl92e_set_key(dev, key_idx, key_idx, KEY_TYPE_WEP104, zero_addr[key_idx], 0, hwkey); rtl92e_set_swcam(dev, key_idx, key_idx, KEY_TYPE_WEP104, diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c index 687dbb04ed2e..2d330d2bbf6d 100644 --- a/drivers/staging/rtl8192e/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c @@ -139,7 +139,7 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, { union delba_param_set DelbaParamSet; struct sk_buff *skb = NULL; - struct rtllib_hdr_3addr *Delba = NULL; + struct rtllib_hdr_3addr *Delba = NULL; u8 *tag = NULL; u16 len = 6 + ieee->tx_headroom; @@ -316,7 +316,7 @@ OnADDBAReq_Fail: int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) { - struct rtllib_hdr_3addr *rsp = NULL; + struct rtllib_hdr_3addr *rsp = NULL; struct ba_record *pPendingBA, *pAdmittedBA; struct tx_ts_record *pTS = NULL; u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; @@ -420,7 +420,7 @@ OnADDBARsp_Reject: int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) { - struct rtllib_hdr_3addr *delba = NULL; + struct rtllib_hdr_3addr *delba = NULL; union delba_param_set *pDelBaParamSet = NULL; u8 *dst = NULL; diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c index f38f1f74fcd6..55da8c9dfe50 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c +++ b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c @@ -285,7 +285,7 @@ static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct rtllib_tkip_data *tkey = priv; - int len; + int len; u8 *pos; struct rtllib_hdr_4addr *hdr; struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index fa580ce1cf43..501ded929329 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -913,7 +913,7 @@ static size_t rtllib_rx_get_hdrlen(struct rtllib_device *ieee, rx_stats->bContainHTC = true; } - if (RTLLIB_QOS_HAS_SEQ(fc)) + if (RTLLIB_QOS_HAS_SEQ(fc)) rx_stats->bIsQosData = true; return hdrlen; -- cgit v1.2.3 From 3262af0024797b1945d94ff677e517769832d462 Mon Sep 17 00:00:00 2001 From: Himadri Pandya Date: Sat, 12 Jan 2019 22:21:48 -0800 Subject: staging: rtl8192e: rename ChannelPlan[] to channel_array[] - style Fix checkpatch.pl warning: CHECK: Avoid CamelCase: Signed-off-by: Himadri Pandya Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/dot11d.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c index 687deac19796..9116d16857c2 100644 --- a/drivers/staging/rtl8192e/dot11d.c +++ b/drivers/staging/rtl8192e/dot11d.c @@ -19,7 +19,7 @@ struct channel_list { u8 Len; }; -static struct channel_list ChannelPlan[] = { +static struct channel_list channel_array[] = { {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 24}, {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, @@ -62,14 +62,14 @@ void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee) ieee->bGlobalDomain = false; - if (ChannelPlan[channel_plan].Len != 0) { + if (channel_array[channel_plan].Len != 0) { memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); - for (i = 0; i < ChannelPlan[channel_plan].Len; i++) { - if (ChannelPlan[channel_plan].channel[i] < min_chan || - ChannelPlan[channel_plan].channel[i] > max_chan) + for (i = 0; i < channel_array[channel_plan].Len; i++) { + if (channel_array[channel_plan].channel[i] < min_chan || + channel_array[channel_plan].channel[i] > max_chan) break; - GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan + GET_DOT11D_INFO(ieee)->channel_map[channel_array [channel_plan].channel[i]] = 1; } } -- cgit v1.2.3 From 75752154039fa65844d529d188083cea9b3ca3e7 Mon Sep 17 00:00:00 2001 From: Himadri Pandya Date: Sat, 12 Jan 2019 22:21:49 -0800 Subject: staging: rtl8192e: rename Len to len - style Fix checkpatch.pl warning: CHECK: Avoid CamelCase: Signed-off-by: Himadri Pandya Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/dot11d.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c index 9116d16857c2..be9a21062a2e 100644 --- a/drivers/staging/rtl8192e/dot11d.c +++ b/drivers/staging/rtl8192e/dot11d.c @@ -16,7 +16,7 @@ struct channel_list { u8 channel[32]; - u8 Len; + u8 len; }; static struct channel_list channel_array[] = { @@ -62,10 +62,10 @@ void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee) ieee->bGlobalDomain = false; - if (channel_array[channel_plan].Len != 0) { + if (channel_array[channel_plan].len != 0) { memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); - for (i = 0; i < channel_array[channel_plan].Len; i++) { + for (i = 0; i < channel_array[channel_plan].len; i++) { if (channel_array[channel_plan].channel[i] < min_chan || channel_array[channel_plan].channel[i] > max_chan) break; -- cgit v1.2.3 From 2b2bbb561f6de45a8d3155e197e46fa199451485 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sun, 13 Jan 2019 19:02:53 +0800 Subject: staging: rtl8712u: Remove dummy reset-resume callback An USB wireless dongle uses rtl8712u stops working after system suspend/resume. When a USB device lost its power during suspend, the USB core knows the power was lost and a reset-resume or a re-probe is required. But rtl8712u provides a dummy reset-resume callback, which gets called and renders the device dead after resume. So remove the reset-resume call back, if power was lost during suspend, let the USB core unbind and probe the device to solve the issue. Signed-off-by: Kai-Heng Feng Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/usb_intf.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 92d75d7c51ae..9cf2a798cfca 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -232,13 +232,6 @@ static int r871x_resume(struct usb_interface *pusb_intf) rtl871x_intf_resume(padapter); return 0; } - -static int r871x_reset_resume(struct usb_interface *pusb_intf) -{ - /* dummy routine */ - return 0; -} - #endif static struct drv_priv drvpriv = { @@ -249,7 +242,6 @@ static struct drv_priv drvpriv = { #ifdef CONFIG_PM .r871xu_drv.suspend = r871x_suspend, .r871xu_drv.resume = r871x_resume, - .r871xu_drv.reset_resume = r871x_reset_resume, #endif }; -- cgit v1.2.3 From ac544a459a95fbded20132cc58bb51663c98114c Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sun, 13 Jan 2019 19:02:54 +0800 Subject: staging: rtl8712u: Fix suspend and resume callbacks When system resume and the rtl8712u dongle didn't lose its power, it doesn't work quite right: [ 146.844241] r8712u 2-3:1.0 wlp0s4f1u3: Unable to resume ... [ 154.029573] r8712u 2-3:1.0 wlp0s4f1u3: In r8711_wx_set_scan: bDriverStopped=1 The !netif_running() check in PM callbacks aren't correct because rtl8712u doesn't support runtime suspend, so the when the PM ops get called, it's system suspend or system resume, hence we want to "stop everthing" or "resume everything". The NULL check on pnetdev is also redundant, the only place pnetdev can become NULL is the disconnect callback, which is mutually exclusive to PM callbacks. This can make rtl8712u starts working after system resume. Signed-off-by: Kai-Heng Feng Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/usb_intf.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 9cf2a798cfca..005010de9997 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -196,10 +196,6 @@ static int r871x_suspend(struct usb_interface *pusb_intf, pm_message_t state) struct _adapter *padapter = netdev_priv(pnetdev); netdev_info(pnetdev, "Suspending...\n"); - if (!pnetdev || !netif_running(pnetdev)) { - netdev_info(pnetdev, "Unable to suspend\n"); - return 0; - } padapter->bSuspended = true; rtl871x_intf_stop(padapter); if (pnetdev->netdev_ops->ndo_stop) @@ -221,10 +217,6 @@ static int r871x_resume(struct usb_interface *pusb_intf) struct _adapter *padapter = netdev_priv(pnetdev); netdev_info(pnetdev, "Resuming...\n"); - if (!pnetdev || !netif_running(pnetdev)) { - netdev_info(pnetdev, "Unable to resume\n"); - return 0; - } netif_device_attach(pnetdev); if (pnetdev->netdev_ops->ndo_open) pnetdev->netdev_ops->ndo_open(pnetdev); -- cgit v1.2.3 From e28dd69ee81be1ce44cc96a61a2172fc503944a4 Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Mon, 14 Jan 2019 20:26:16 +0530 Subject: staging: greybus: gpio: switch GPIO portions to use GPIOLIB_IRQCHIP Convert the GPIO driver to use the GPIO irqchip library GPIOLIB_IRQCHIP instead of reimplementing the same. Reviewed-by: Johan Hovold Signed-off-by: Nishad Kamdar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/Kconfig | 1 + drivers/staging/greybus/TODO | 2 - drivers/staging/greybus/gpio.c | 156 +++------------------------------------- 3 files changed, 11 insertions(+), 148 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/greybus/Kconfig b/drivers/staging/greybus/Kconfig index ab096bcef98c..b571e4e8060b 100644 --- a/drivers/staging/greybus/Kconfig +++ b/drivers/staging/greybus/Kconfig @@ -148,6 +148,7 @@ if GREYBUS_BRIDGED_PHY config GREYBUS_GPIO tristate "Greybus GPIO Bridged PHY driver" depends on GPIOLIB + select GPIOLIB_IRQCHIP ---help--- Select this option if you have a device that follows the Greybus GPIO Bridged PHY Class specification. diff --git a/drivers/staging/greybus/TODO b/drivers/staging/greybus/TODO index 3b90a5711998..31f1f2cb401c 100644 --- a/drivers/staging/greybus/TODO +++ b/drivers/staging/greybus/TODO @@ -1,5 +1,3 @@ * Convert all uses of the old GPIO API from to the GPIO descriptor API in and look up GPIO lines from device tree or ACPI. -* Convert the GPIO driver to use the GPIO irqchip library - GPIOLIB_IRQCHIP instead of reimplementing the same. diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c index e110681e6f86..3151004d26fb 100644 --- a/drivers/staging/greybus/gpio.c +++ b/drivers/staging/greybus/gpio.c @@ -9,9 +9,9 @@ #include #include #include -#include #include #include +#include #include #include "greybus.h" @@ -39,11 +39,6 @@ struct gb_gpio_controller { struct gpio_chip chip; struct irq_chip irqc; - struct irq_chip *irqchip; - struct irq_domain *irqdomain; - unsigned int irq_base; - irq_flow_handler_t irq_handler; - unsigned int irq_default_type; struct mutex irq_lock; }; #define gpio_chip_to_gb_gpio_controller(chip) \ @@ -391,7 +386,7 @@ static int gb_gpio_request_handler(struct gb_operation *op) return -EINVAL; } - irq = irq_find_mapping(ggc->irqdomain, event->which); + irq = irq_find_mapping(ggc->chip.irq.domain, event->which); if (!irq) { dev_err(dev, "failed to find IRQ\n"); return -EINVAL; @@ -506,135 +501,6 @@ static int gb_gpio_controller_setup(struct gb_gpio_controller *ggc) return ret; } -/** - * gb_gpio_irq_map() - maps an IRQ into a GB gpio irqchip - * @d: the irqdomain used by this irqchip - * @irq: the global irq number used by this GB gpio irqchip irq - * @hwirq: the local IRQ/GPIO line offset on this GB gpio - * - * This function will set up the mapping for a certain IRQ line on a - * GB gpio by assigning the GB gpio as chip data, and using the irqchip - * stored inside the GB gpio. - */ -static int gb_gpio_irq_map(struct irq_domain *domain, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct gpio_chip *chip = domain->host_data; - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); - - irq_set_chip_data(irq, ggc); - irq_set_chip_and_handler(irq, ggc->irqchip, ggc->irq_handler); - irq_set_noprobe(irq); - /* - * No set-up of the hardware will happen if IRQ_TYPE_NONE - * is passed as default type. - */ - if (ggc->irq_default_type != IRQ_TYPE_NONE) - irq_set_irq_type(irq, ggc->irq_default_type); - - return 0; -} - -static void gb_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) -{ - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); -} - -static const struct irq_domain_ops gb_gpio_domain_ops = { - .map = gb_gpio_irq_map, - .unmap = gb_gpio_irq_unmap, -}; - -/** - * gb_gpio_irqchip_remove() - removes an irqchip added to a gb_gpio_controller - * @ggc: the gb_gpio_controller to remove the irqchip from - * - * This is called only from gb_gpio_remove() - */ -static void gb_gpio_irqchip_remove(struct gb_gpio_controller *ggc) -{ - unsigned int offset; - - /* Remove all IRQ mappings and delete the domain */ - if (ggc->irqdomain) { - for (offset = 0; offset < (ggc->line_max + 1); offset++) - irq_dispose_mapping(irq_find_mapping(ggc->irqdomain, - offset)); - irq_domain_remove(ggc->irqdomain); - } - - if (ggc->irqchip) - ggc->irqchip = NULL; -} - -/** - * gb_gpio_irqchip_add() - adds an irqchip to a gpio chip - * @chip: the gpio chip to add the irqchip to - * @irqchip: the irqchip to add to the adapter - * @first_irq: if not dynamically assigned, the base (first) IRQ to - * allocate gpio irqs from - * @handler: the irq handler to use (often a predefined irq core function) - * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE - * to have the core avoid setting up any default type in the hardware. - * - * This function closely associates a certain irqchip with a certain - * gpio chip, providing an irq domain to translate the local IRQs to - * global irqs, and making sure that the gpio chip - * is passed as chip data to all related functions. Driver callbacks - * need to use container_of() to get their local state containers back - * from the gpio chip passed as chip data. An irqdomain will be stored - * in the gpio chip that shall be used by the driver to handle IRQ number - * translation. The gpio chip will need to be initialized and registered - * before calling this function. - */ -static int gb_gpio_irqchip_add(struct gpio_chip *chip, - struct irq_chip *irqchip, - unsigned int first_irq, - irq_flow_handler_t handler, - unsigned int type) -{ - struct gb_gpio_controller *ggc; - unsigned int offset; - unsigned int irq_base; - - if (!chip || !irqchip) - return -EINVAL; - - ggc = gpio_chip_to_gb_gpio_controller(chip); - - ggc->irqchip = irqchip; - ggc->irq_handler = handler; - ggc->irq_default_type = type; - ggc->irqdomain = irq_domain_add_simple(NULL, - ggc->line_max + 1, first_irq, - &gb_gpio_domain_ops, chip); - if (!ggc->irqdomain) { - ggc->irqchip = NULL; - return -EINVAL; - } - - /* - * Prepare the mapping since the irqchip shall be orthogonal to - * any gpio calls. If the first_irq was zero, this is - * necessary to allocate descriptors for all IRQs. - */ - for (offset = 0; offset < (ggc->line_max + 1); offset++) { - irq_base = irq_create_mapping(ggc->irqdomain, offset); - if (offset == 0) - ggc->irq_base = irq_base; - } - - return 0; -} - -static int gb_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); - - return irq_find_mapping(ggc->irqdomain, offset); -} - static int gb_gpio_probe(struct gbphy_device *gbphy_dev, const struct gbphy_device_id *id) { @@ -694,7 +560,6 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev, gpio->get = gb_gpio_get; gpio->set = gb_gpio_set; gpio->set_config = gb_gpio_set_config; - gpio->to_irq = gb_gpio_to_irq; gpio->base = -1; /* Allocate base dynamically */ gpio->ngpio = ggc->line_max + 1; gpio->can_sleep = true; @@ -703,24 +568,24 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev, if (ret) goto exit_line_free; - ret = gb_gpio_irqchip_add(gpio, irqc, 0, - handle_level_irq, IRQ_TYPE_NONE); + ret = gpiochip_add(gpio); if (ret) { - dev_err(&gbphy_dev->dev, "failed to add irq chip: %d\n", ret); + dev_err(&gbphy_dev->dev, "failed to add gpio chip: %d\n", ret); goto exit_line_free; } - ret = gpiochip_add(gpio); + ret = gpiochip_irqchip_add(gpio, irqc, 0, handle_level_irq, + IRQ_TYPE_NONE); if (ret) { - dev_err(&gbphy_dev->dev, "failed to add gpio chip: %d\n", ret); - goto exit_gpio_irqchip_remove; + dev_err(&gbphy_dev->dev, "failed to add irq chip: %d\n", ret); + goto exit_gpiochip_remove; } gbphy_runtime_put_autosuspend(gbphy_dev); return 0; -exit_gpio_irqchip_remove: - gb_gpio_irqchip_remove(ggc); +exit_gpiochip_remove: + gpiochip_remove(gpio); exit_line_free: kfree(ggc->lines); exit_connection_disable: @@ -744,7 +609,6 @@ static void gb_gpio_remove(struct gbphy_device *gbphy_dev) gb_connection_disable_rx(connection); gpiochip_remove(&ggc->chip); - gb_gpio_irqchip_remove(ggc); gb_connection_disable(connection); gb_connection_destroy(connection); kfree(ggc->lines); -- cgit v1.2.3 From fbacec8f2a0e05dd72de475224f3ab1c705c70fb Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Mon, 14 Jan 2019 20:27:31 +0530 Subject: staging: greybus: arche-apb-ctrl.c: Switch to the gpio descriptor interface Use the gpiod interface instead of the deprecated old non-descriptor interface while continuing to ignore gpio flags from device tree in functions "deassert_reset()" and "assert_reset()" for now. Reviewed-by: Johan Hovold Signed-off-by: Nishad Kamdar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/arche-apb-ctrl.c | 152 +++++++++++++------------------ 1 file changed, 61 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c index be5ffed90bcf..bbf3ba744fc4 100644 --- a/drivers/staging/greybus/arche-apb-ctrl.c +++ b/drivers/staging/greybus/arche-apb-ctrl.c @@ -8,9 +8,8 @@ #include #include -#include +#include #include -#include #include #include #include @@ -24,12 +23,12 @@ static void apb_bootret_deassert(struct device *dev); struct arche_apb_ctrl_drvdata { /* Control GPIO signals to and from AP <=> AP Bridges */ - int resetn_gpio; - int boot_ret_gpio; - int pwroff_gpio; - int wake_in_gpio; - int wake_out_gpio; - int pwrdn_gpio; + struct gpio_desc *resetn; + struct gpio_desc *boot_ret; + struct gpio_desc *pwroff; + struct gpio_desc *wake_in; + struct gpio_desc *wake_out; + struct gpio_desc *pwrdn; enum arche_platform_state state; bool init_disabled; @@ -37,28 +36,28 @@ struct arche_apb_ctrl_drvdata { struct regulator *vcore; struct regulator *vio; - int clk_en_gpio; + struct gpio_desc *clk_en; struct clk *clk; struct pinctrl *pinctrl; struct pinctrl_state *pin_default; /* V2: SPI Bus control */ - int spi_en_gpio; + struct gpio_desc *spi_en; bool spi_en_polarity_high; }; /* * Note that these low level api's are active high */ -static inline void deassert_reset(unsigned int gpio) +static inline void deassert_reset(struct gpio_desc *gpio) { - gpio_set_value(gpio, 1); + gpiod_set_raw_value(gpio, 1); } -static inline void assert_reset(unsigned int gpio) +static inline void assert_reset(struct gpio_desc *gpio) { - gpio_set_value(gpio, 0); + gpiod_set_raw_value(gpio, 0); } /* @@ -75,11 +74,10 @@ static int coldboot_seq(struct platform_device *pdev) return 0; /* Hold APB in reset state */ - assert_reset(apb->resetn_gpio); + assert_reset(apb->resetn); - if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && - gpio_is_valid(apb->spi_en_gpio)) - devm_gpio_free(dev, apb->spi_en_gpio); + if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && apb->spi_en) + devm_gpiod_put(dev, apb->spi_en); /* Enable power to APB */ if (!IS_ERR(apb->vcore)) { @@ -101,13 +99,13 @@ static int coldboot_seq(struct platform_device *pdev) apb_bootret_deassert(dev); /* On DB3 clock was not mandatory */ - if (gpio_is_valid(apb->clk_en_gpio)) - gpio_set_value(apb->clk_en_gpio, 1); + if (apb->clk_en) + gpiod_set_value(apb->clk_en, 1); usleep_range(100, 200); /* deassert reset to APB : Active-low signal */ - deassert_reset(apb->resetn_gpio); + deassert_reset(apb->resetn); apb->state = ARCHE_PLATFORM_STATE_ACTIVE; @@ -136,25 +134,25 @@ static int fw_flashing_seq(struct platform_device *pdev) return ret; } - if (gpio_is_valid(apb->spi_en_gpio)) { + if (apb->spi_en) { unsigned long flags; if (apb->spi_en_polarity_high) - flags = GPIOF_OUT_INIT_HIGH; + flags = GPIOD_OUT_HIGH; else - flags = GPIOF_OUT_INIT_LOW; + flags = GPIOD_OUT_LOW; - ret = devm_gpio_request_one(dev, apb->spi_en_gpio, - flags, "apb_spi_en"); - if (ret) { - dev_err(dev, "Failed requesting SPI bus en gpio %d\n", - apb->spi_en_gpio); + apb->spi_en = devm_gpiod_get(dev, "spi-en", flags); + if (IS_ERR(apb->spi_en)) { + ret = PTR_ERR(apb->spi_en); + dev_err(dev, "Failed requesting SPI bus en GPIO: %d\n", + ret); return ret; } } /* for flashing device should be in reset state */ - assert_reset(apb->resetn_gpio); + assert_reset(apb->resetn); apb->state = ARCHE_PLATFORM_STATE_FW_FLASHING; return 0; @@ -176,9 +174,8 @@ static int standby_boot_seq(struct platform_device *pdev) apb->state == ARCHE_PLATFORM_STATE_OFF) return 0; - if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && - gpio_is_valid(apb->spi_en_gpio)) - devm_gpio_free(dev, apb->spi_en_gpio); + if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && apb->spi_en) + devm_gpiod_put(dev, apb->spi_en); /* * As per WDM spec, do nothing @@ -201,13 +198,12 @@ static void poweroff_seq(struct platform_device *pdev) if (apb->init_disabled || apb->state == ARCHE_PLATFORM_STATE_OFF) return; - if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && - gpio_is_valid(apb->spi_en_gpio)) - devm_gpio_free(dev, apb->spi_en_gpio); + if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && apb->spi_en) + devm_gpiod_put(dev, apb->spi_en); /* disable the clock */ - if (gpio_is_valid(apb->clk_en_gpio)) - gpio_set_value(apb->clk_en_gpio, 0); + if (apb->clk_en) + gpiod_set_value(apb->clk_en, 0); if (!IS_ERR(apb->vcore) && regulator_is_enabled(apb->vcore) > 0) regulator_disable(apb->vcore); @@ -216,7 +212,7 @@ static void poweroff_seq(struct platform_device *pdev) regulator_disable(apb->vio); /* As part of exit, put APB back in reset state */ - assert_reset(apb->resetn_gpio); + assert_reset(apb->resetn); apb->state = ARCHE_PLATFORM_STATE_OFF; /* TODO: May have to send an event to SVC about this exit */ @@ -226,7 +222,7 @@ static void apb_bootret_deassert(struct device *dev) { struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev); - gpio_set_value(apb->boot_ret_gpio, 0); + gpiod_set_value(apb->boot_ret, 0); } int apb_ctrl_coldboot(struct device *dev) @@ -322,66 +318,44 @@ static int apb_ctrl_get_devtree_data(struct platform_device *pdev, struct arche_apb_ctrl_drvdata *apb) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; int ret; - apb->resetn_gpio = of_get_named_gpio(np, "reset-gpios", 0); - if (apb->resetn_gpio < 0) { - dev_err(dev, "failed to get reset gpio\n"); - return apb->resetn_gpio; - } - ret = devm_gpio_request_one(dev, apb->resetn_gpio, - GPIOF_OUT_INIT_LOW, "apb-reset"); - if (ret) { - dev_err(dev, "Failed requesting reset gpio %d\n", - apb->resetn_gpio); + apb->resetn = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(apb->resetn)) { + ret = PTR_ERR(apb->resetn); + dev_err(dev, "Failed requesting reset GPIO: %d\n", ret); return ret; } - apb->boot_ret_gpio = of_get_named_gpio(np, "boot-ret-gpios", 0); - if (apb->boot_ret_gpio < 0) { - dev_err(dev, "failed to get boot retention gpio\n"); - return apb->boot_ret_gpio; - } - ret = devm_gpio_request_one(dev, apb->boot_ret_gpio, - GPIOF_OUT_INIT_LOW, "boot retention"); - if (ret) { - dev_err(dev, "Failed requesting bootret gpio %d\n", - apb->boot_ret_gpio); + apb->boot_ret = devm_gpiod_get(dev, "boot-ret", GPIOD_OUT_LOW); + if (IS_ERR(apb->boot_ret)) { + ret = PTR_ERR(apb->boot_ret); + dev_err(dev, "Failed requesting bootret GPIO: %d\n", ret); return ret; } /* It's not mandatory to support power management interface */ - apb->pwroff_gpio = of_get_named_gpio(np, "pwr-off-gpios", 0); - if (apb->pwroff_gpio < 0) { - dev_err(dev, "failed to get power off gpio\n"); - return apb->pwroff_gpio; - } - ret = devm_gpio_request_one(dev, apb->pwroff_gpio, - GPIOF_IN, "pwroff_n"); - if (ret) { - dev_err(dev, "Failed requesting pwroff_n gpio %d\n", - apb->pwroff_gpio); + apb->pwroff = devm_gpiod_get_optional(dev, "pwr-off", GPIOD_IN); + if (IS_ERR(apb->pwroff)) { + ret = PTR_ERR(apb->pwroff); + dev_err(dev, "Failed requesting pwroff_n GPIO: %d\n", ret); return ret; } /* Do not make clock mandatory as of now (for DB3) */ - apb->clk_en_gpio = of_get_named_gpio(np, "clock-en-gpio", 0); - if (apb->clk_en_gpio < 0) { - dev_warn(dev, "failed to get clock en gpio\n"); - } else if (gpio_is_valid(apb->clk_en_gpio)) { - ret = devm_gpio_request_one(dev, apb->clk_en_gpio, - GPIOF_OUT_INIT_LOW, "apb_clk_en"); - if (ret) { - dev_warn(dev, "Failed requesting APB clock en gpio %d\n", - apb->clk_en_gpio); - return ret; - } + apb->clk_en = devm_gpiod_get_optional(dev, "clock-en", GPIOD_OUT_LOW); + if (IS_ERR(apb->clk_en)) { + ret = PTR_ERR(apb->clk_en); + dev_err(dev, "Failed requesting APB clock en GPIO: %d\n", ret); + return ret; } - apb->pwrdn_gpio = of_get_named_gpio(np, "pwr-down-gpios", 0); - if (apb->pwrdn_gpio < 0) - dev_warn(dev, "failed to get power down gpio\n"); + apb->pwrdn = devm_gpiod_get(dev, "pwr-down", GPIOD_OUT_LOW); + if (IS_ERR(apb->pwrdn)) { + ret = PTR_ERR(apb->pwrdn); + dev_warn(dev, "Failed requesting power down GPIO: %d\n", ret); + return ret; + } /* Regulators are optional, as we may have fixed supply coming in */ apb->vcore = devm_regulator_get(dev, "vcore"); @@ -404,12 +378,8 @@ static int apb_ctrl_get_devtree_data(struct platform_device *pdev, } /* Only applicable for platform >= V2 */ - apb->spi_en_gpio = of_get_named_gpio(np, "spi-en-gpio", 0); - if (apb->spi_en_gpio >= 0) { - if (of_property_read_bool(pdev->dev.of_node, - "spi-en-active-high")) - apb->spi_en_polarity_high = true; - } + if (of_property_read_bool(pdev->dev.of_node, "gb,spi-en-active-high")) + apb->spi_en_polarity_high = true; return 0; } -- cgit v1.2.3 From 4207b5870da5b79a7831cbead2cb60daeab7d64f Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Mon, 14 Jan 2019 20:28:59 +0530 Subject: staging: greybus: arche-platform: Switch to the gpio descriptor interface Use the gpiod interface instead of the deprecated old non-descriptor interface while continuing to ignore gpio flags from device tree in "svc_reset_onoff()" for now. Reviewed-by: Johan Hovold Signed-off-by: Nishad Kamdar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/arche-platform.c | 124 ++++++++++--------------------- 1 file changed, 41 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c index 4c36e88766e7..6eb842040c22 100644 --- a/drivers/staging/greybus/arche-platform.c +++ b/drivers/staging/greybus/arche-platform.c @@ -8,10 +8,9 @@ #include #include -#include +#include #include #include -#include #include #include #include @@ -45,14 +44,14 @@ enum svc_wakedetect_state { struct arche_platform_drvdata { /* Control GPIO signals to and from AP <=> SVC */ - int svc_reset_gpio; + struct gpio_desc *svc_reset; bool is_reset_act_hi; - int svc_sysboot_gpio; - int wake_detect_gpio; /* bi-dir,maps to WAKE_MOD & WAKE_FRAME signals */ + struct gpio_desc *svc_sysboot; + struct gpio_desc *wake_detect; /* bi-dir,maps to WAKE_MOD & WAKE_FRAME signals */ enum arche_platform_state state; - int svc_refclk_req; + struct gpio_desc *svc_refclk_req; struct clk *svc_ref_clk; struct pinctrl *pinctrl; @@ -85,9 +84,9 @@ static void arche_platform_set_wake_detect_state( arche_pdata->wake_detect_state = state; } -static inline void svc_reset_onoff(unsigned int gpio, bool onoff) +static inline void svc_reset_onoff(struct gpio_desc *gpio, bool onoff) { - gpio_set_value(gpio, onoff); + gpiod_set_raw_value(gpio, onoff); } static int apb_cold_boot(struct device *dev, void *data) @@ -116,7 +115,6 @@ static int apb_poweroff(struct device *dev, void *data) static void arche_platform_wd_irq_en(struct arche_platform_drvdata *arche_pdata) { /* Enable interrupt here, to read event back from SVC */ - gpio_direction_input(arche_pdata->wake_detect_gpio); enable_irq(arche_pdata->wake_detect_irq); } @@ -160,7 +158,7 @@ static irqreturn_t arche_platform_wd_irq(int irq, void *devid) spin_lock_irqsave(&arche_pdata->wake_lock, flags); - if (gpio_get_value(arche_pdata->wake_detect_gpio)) { + if (gpiod_get_value(arche_pdata->wake_detect)) { /* wake/detect rising */ /* @@ -224,10 +222,9 @@ arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata) dev_info(arche_pdata->dev, "Booting from cold boot state\n"); - svc_reset_onoff(arche_pdata->svc_reset_gpio, - arche_pdata->is_reset_act_hi); + svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi); - gpio_set_value(arche_pdata->svc_sysboot_gpio, 0); + gpiod_set_value(arche_pdata->svc_sysboot, 0); usleep_range(100, 200); ret = clk_prepare_enable(arche_pdata->svc_ref_clk); @@ -238,8 +235,7 @@ arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata) } /* bring SVC out of reset */ - svc_reset_onoff(arche_pdata->svc_reset_gpio, - !arche_pdata->is_reset_act_hi); + svc_reset_onoff(arche_pdata->svc_reset, !arche_pdata->is_reset_act_hi); arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_ACTIVE); @@ -259,10 +255,9 @@ arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata) dev_info(arche_pdata->dev, "Switching to FW flashing state\n"); - svc_reset_onoff(arche_pdata->svc_reset_gpio, - arche_pdata->is_reset_act_hi); + svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi); - gpio_set_value(arche_pdata->svc_sysboot_gpio, 1); + gpiod_set_value(arche_pdata->svc_sysboot, 1); usleep_range(100, 200); @@ -273,8 +268,7 @@ arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata) return ret; } - svc_reset_onoff(arche_pdata->svc_reset_gpio, - !arche_pdata->is_reset_act_hi); + svc_reset_onoff(arche_pdata->svc_reset, !arche_pdata->is_reset_act_hi); arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_FW_FLASHING); @@ -305,8 +299,7 @@ arche_platform_poweroff_seq(struct arche_platform_drvdata *arche_pdata) clk_disable_unprepare(arche_pdata->svc_ref_clk); /* As part of exit, put APB back in reset state */ - svc_reset_onoff(arche_pdata->svc_reset_gpio, - arche_pdata->is_reset_act_hi); + svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi); arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF); } @@ -435,6 +428,7 @@ static int arche_platform_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; int ret; + unsigned int flags; arche_pdata = devm_kzalloc(&pdev->dev, sizeof(*arche_pdata), GFP_KERNEL); @@ -444,61 +438,33 @@ static int arche_platform_probe(struct platform_device *pdev) /* setup svc reset gpio */ arche_pdata->is_reset_act_hi = of_property_read_bool(np, "svc,reset-active-high"); - arche_pdata->svc_reset_gpio = of_get_named_gpio(np, - "svc,reset-gpio", - 0); - if (!gpio_is_valid(arche_pdata->svc_reset_gpio)) { - dev_err(dev, "failed to get reset-gpio\n"); - return arche_pdata->svc_reset_gpio; - } - ret = devm_gpio_request(dev, arche_pdata->svc_reset_gpio, "svc-reset"); - if (ret) { - dev_err(dev, "failed to request svc-reset gpio:%d\n", ret); - return ret; - } - ret = gpio_direction_output(arche_pdata->svc_reset_gpio, - arche_pdata->is_reset_act_hi); - if (ret) { - dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret); + if (arche_pdata->is_reset_act_hi) + flags = GPIOD_OUT_HIGH; + else + flags = GPIOD_OUT_LOW; + + arche_pdata->svc_reset = devm_gpiod_get(dev, "svc,reset", flags); + if (IS_ERR(arche_pdata->svc_reset)) { + ret = PTR_ERR(arche_pdata->svc_reset); + dev_err(dev, "failed to request svc-reset GPIO: %d\n", ret); return ret; } arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF); - arche_pdata->svc_sysboot_gpio = of_get_named_gpio(np, - "svc,sysboot-gpio", - 0); - if (!gpio_is_valid(arche_pdata->svc_sysboot_gpio)) { - dev_err(dev, "failed to get sysboot gpio\n"); - return arche_pdata->svc_sysboot_gpio; - } - ret = devm_gpio_request(dev, arche_pdata->svc_sysboot_gpio, "sysboot0"); - if (ret) { - dev_err(dev, "failed to request sysboot0 gpio:%d\n", ret); - return ret; - } - ret = gpio_direction_output(arche_pdata->svc_sysboot_gpio, 0); - if (ret) { - dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret); + arche_pdata->svc_sysboot = devm_gpiod_get(dev, "svc,sysboot", + GPIOD_OUT_LOW); + if (IS_ERR(arche_pdata->svc_sysboot)) { + ret = PTR_ERR(arche_pdata->svc_sysboot); + dev_err(dev, "failed to request sysboot0 GPIO: %d\n", ret); return ret; } /* setup the clock request gpio first */ - arche_pdata->svc_refclk_req = of_get_named_gpio(np, - "svc,refclk-req-gpio", - 0); - if (!gpio_is_valid(arche_pdata->svc_refclk_req)) { - dev_err(dev, "failed to get svc clock-req gpio\n"); - return arche_pdata->svc_refclk_req; - } - ret = devm_gpio_request(dev, arche_pdata->svc_refclk_req, - "svc-clk-req"); - if (ret) { - dev_err(dev, "failed to request svc-clk-req gpio: %d\n", ret); - return ret; - } - ret = gpio_direction_input(arche_pdata->svc_refclk_req); - if (ret) { - dev_err(dev, "failed to set svc-clk-req gpio dir :%d\n", ret); + arche_pdata->svc_refclk_req = devm_gpiod_get(dev, "svc,refclk-req", + GPIOD_IN); + if (IS_ERR(arche_pdata->svc_refclk_req)) { + ret = PTR_ERR(arche_pdata->svc_refclk_req); + dev_err(dev, "failed to request svc-clk-req GPIO: %d\n", ret); return ret; } @@ -515,19 +481,11 @@ static int arche_platform_probe(struct platform_device *pdev) arche_pdata->num_apbs = of_get_child_count(np); dev_dbg(dev, "Number of APB's available - %d\n", arche_pdata->num_apbs); - arche_pdata->wake_detect_gpio = of_get_named_gpio(np, - "svc,wake-detect-gpio", - 0); - if (arche_pdata->wake_detect_gpio < 0) { - dev_err(dev, "failed to get wake detect gpio\n"); - return arche_pdata->wake_detect_gpio; - } - - ret = devm_gpio_request(dev, arche_pdata->wake_detect_gpio, - "wake detect"); - if (ret) { - dev_err(dev, "Failed requesting wake_detect gpio %d\n", - arche_pdata->wake_detect_gpio); + arche_pdata->wake_detect = devm_gpiod_get(dev, "svc,wake-detect", + GPIOD_IN); + if (IS_ERR(arche_pdata->wake_detect)) { + ret = PTR_ERR(arche_pdata->wake_detect); + dev_err(dev, "Failed requesting wake_detect GPIO: %d\n", ret); return ret; } @@ -538,7 +496,7 @@ static int arche_platform_probe(struct platform_device *pdev) spin_lock_init(&arche_pdata->wake_lock); mutex_init(&arche_pdata->platform_state_mutex); arche_pdata->wake_detect_irq = - gpio_to_irq(arche_pdata->wake_detect_gpio); + gpiod_to_irq(arche_pdata->wake_detect); ret = devm_request_threaded_irq(dev, arche_pdata->wake_detect_irq, arche_platform_wd_irq, -- cgit v1.2.3 From e94e6d1454e4cd25c4482de89b0607580d82d625 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Tue, 15 Jan 2019 09:24:00 +0100 Subject: staging: rtl8188eu: remove unnecessary parentheses in os_intfs.c Remove unnecessary parentheses reported by checkpatch. Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/os_intfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index abcce2240f15..6681383579ee 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -198,8 +198,8 @@ static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev) { struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct recv_priv *precvpriv = &(padapter->recvpriv); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct recv_priv *precvpriv = &padapter->recvpriv; padapter->stats.tx_packets = pxmitpriv->tx_pkts; padapter->stats.rx_packets = precvpriv->rx_pkts; -- cgit v1.2.3 From 48101806c52203f64c6a76e74c1c68abd57903c2 Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Thu, 27 Dec 2018 22:51:29 +0530 Subject: Staging: emxx_udc: Switch to the gpio descriptor interface Convert VBUS GPIO to use GPIO descriptors from and stop using the old GPIO API. Signed-off-by: Nishad Kamdar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/emxx_udc/emxx_udc.c | 31 ++++++++++++++++--------------- drivers/staging/emxx_udc/emxx_udc.h | 2 ++ 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index 8e8f57c4f029..a913d40f0801 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include "emxx_udc.h" @@ -2220,7 +2220,7 @@ static inline void _nbu2ss_check_vbus(struct nbu2ss_udc *udc) mdelay(VBUS_CHATTERING_MDELAY); /* wait (ms) */ /* VBUS ON Check*/ - reg_dt = gpio_get_value(VBUS_VALUE); + reg_dt = gpiod_get_value(vbus_gpio); if (reg_dt == 0) { udc->linux_suspended = 0; @@ -2247,7 +2247,7 @@ static inline void _nbu2ss_check_vbus(struct nbu2ss_udc *udc) } } else { mdelay(5); /* wait (5ms) */ - reg_dt = gpio_get_value(VBUS_VALUE); + reg_dt = gpiod_get_value(vbus_gpio); if (reg_dt == 0) return; @@ -2311,7 +2311,7 @@ static inline void _nbu2ss_int_usb_suspend(struct nbu2ss_udc *udc) u32 reg_dt; if (udc->usb_suspended == 0) { - reg_dt = gpio_get_value(VBUS_VALUE); + reg_dt = gpiod_get_value(vbus_gpio); if (reg_dt == 0) return; @@ -2351,7 +2351,7 @@ static irqreturn_t _nbu2ss_udc_irq(int irq, void *_udc) struct nbu2ss_udc *udc = (struct nbu2ss_udc *)_udc; struct fc_regs __iomem *preg = udc->p_regs; - if (gpio_get_value(VBUS_VALUE) == 0) { + if (gpiod_get_value(vbus_gpio) == 0) { _nbu2ss_writel(&preg->USB_INT_STA, ~USB_INT_STA_RW); _nbu2ss_writel(&preg->USB_INT_ENA, 0); return IRQ_HANDLED; @@ -2360,7 +2360,7 @@ static irqreturn_t _nbu2ss_udc_irq(int irq, void *_udc) spin_lock(&udc->lock); for (;;) { - if (gpio_get_value(VBUS_VALUE) == 0) { + if (gpiod_get_value(vbus_gpio) == 0) { _nbu2ss_writel(&preg->USB_INT_STA, ~USB_INT_STA_RW); _nbu2ss_writel(&preg->USB_INT_ENA, 0); status = 0; @@ -2750,7 +2750,7 @@ static int nbu2ss_ep_fifo_status(struct usb_ep *_ep) preg = udc->p_regs; - data = gpio_get_value(VBUS_VALUE); + data = gpiod_get_value(vbus_gpio); if (data == 0) return -EINVAL; @@ -2790,7 +2790,7 @@ static void nbu2ss_ep_fifo_flush(struct usb_ep *_ep) return; } - data = gpio_get_value(VBUS_VALUE); + data = gpiod_get_value(vbus_gpio); if (data == 0) return; @@ -2832,7 +2832,7 @@ static int nbu2ss_gad_get_frame(struct usb_gadget *pgadget) } udc = container_of(pgadget, struct nbu2ss_udc, gadget); - data = gpio_get_value(VBUS_VALUE); + data = gpiod_get_value(vbus_gpio); if (data == 0) return -EINVAL; @@ -2854,7 +2854,7 @@ static int nbu2ss_gad_wakeup(struct usb_gadget *pgadget) udc = container_of(pgadget, struct nbu2ss_udc, gadget); - data = gpio_get_value(VBUS_VALUE); + data = gpiod_get_value(vbus_gpio); if (data == 0) { dev_warn(&pgadget->dev, "VBUS LEVEL = %d\n", data); return -EINVAL; @@ -3119,12 +3119,13 @@ static int nbu2ss_drv_probe(struct platform_device *pdev) } /* VBUS Interrupt */ - irq_set_irq_type(INT_VBUS, IRQ_TYPE_EDGE_BOTH); - status = request_irq(INT_VBUS, + vbus_irq = gpiod_to_irq(vbus_gpio); + irq_set_irq_type(vbus_irq, IRQ_TYPE_EDGE_BOTH); + status = request_irq(vbus_irq, _nbu2ss_vbus_irq, IRQF_SHARED, driver_name, udc); if (status != 0) { - dev_err(udc->dev, "request_irq(INT_VBUS) failed\n"); + dev_err(udc->dev, "request_irq(vbus_irq) failed\n"); return status; } @@ -3160,7 +3161,7 @@ static int nbu2ss_drv_remove(struct platform_device *pdev) } /* Interrupt Handler - Release */ - free_irq(INT_VBUS, udc); + free_irq(vbus_irq, udc); return 0; } @@ -3201,7 +3202,7 @@ static int nbu2ss_drv_resume(struct platform_device *pdev) if (!udc) return 0; - data = gpio_get_value(VBUS_VALUE); + data = gpiod_get_value(vbus_gpio); if (data) { udc->vbus_active = 1; udc->devstate = USB_STATE_POWERED; diff --git a/drivers/staging/emxx_udc/emxx_udc.h b/drivers/staging/emxx_udc/emxx_udc.h index e28a74da9633..b8c3dee5626c 100644 --- a/drivers/staging/emxx_udc/emxx_udc.h +++ b/drivers/staging/emxx_udc/emxx_udc.h @@ -30,6 +30,8 @@ /* below hacked up for staging integration */ #define GPIO_VBUS 0 /* GPIO_P153 on KZM9D */ #define INT_VBUS 0 /* IRQ for GPIO_P153 */ +struct gpio_desc *vbus_gpio; +int vbus_irq; /*------------ Board dependence(Wait) */ -- cgit v1.2.3 From d6b1090546450d9c34e64ed6f4cdbc6856db2f94 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Thu, 10 Jan 2019 17:43:36 -0700 Subject: staging: Move ralink-gdma to its own directory This is in preparation to allow it and the mt7621-dma drivers to be built separately. They are completely independent pieces of software, and the Kconfig specifies very different requirements. Cc: linux-kernel@vger.kernel.org Cc: devel@driverdev.osuosl.org Cc: Neil Brown Signed-off-by: George Hilliard Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/mt7621-dma/Kconfig | 6 - drivers/staging/mt7621-dma/Makefile | 1 - drivers/staging/mt7621-dma/ralink-gdma.c | 932 ------------------------------ drivers/staging/ralink-gdma/Kconfig | 6 + drivers/staging/ralink-gdma/Makefile | 3 + drivers/staging/ralink-gdma/ralink-gdma.c | 932 ++++++++++++++++++++++++++++++ 8 files changed, 944 insertions(+), 939 deletions(-) delete mode 100644 drivers/staging/mt7621-dma/ralink-gdma.c create mode 100644 drivers/staging/ralink-gdma/Kconfig create mode 100644 drivers/staging/ralink-gdma/Makefile create mode 100644 drivers/staging/ralink-gdma/ralink-gdma.c (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 4a3d6e00f7cb..46af55acda16 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -112,6 +112,8 @@ source "drivers/staging/mt7621-spi/Kconfig" source "drivers/staging/mt7621-dma/Kconfig" +source "drivers/staging/ralink-gdma/Kconfig" + source "drivers/staging/mt7621-mmc/Kconfig" source "drivers/staging/mt7621-eth/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 413890dd5a14..4d563ed0bc79 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SOC_MT7621) += mt7621-pci-phy/ obj-$(CONFIG_SOC_MT7621) += mt7621-pinctrl/ obj-$(CONFIG_SOC_MT7621) += mt7621-spi/ obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ +obj-$(CONFIG_SOC_MT7621) += ralink-gdma/ obj-$(CONFIG_SOC_MT7621) += mt7621-mmc/ obj-$(CONFIG_SOC_MT7621) += mt7621-eth/ obj-$(CONFIG_SOC_MT7621) += mt7621-dts/ diff --git a/drivers/staging/mt7621-dma/Kconfig b/drivers/staging/mt7621-dma/Kconfig index 2423c40099d1..b6e48a682c44 100644 --- a/drivers/staging/mt7621-dma/Kconfig +++ b/drivers/staging/mt7621-dma/Kconfig @@ -1,9 +1,3 @@ -config DMA_RALINK - tristate "RALINK DMA support" - depends on RALINK && !SOC_RT288X - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - config MTK_HSDMA tristate "MTK HSDMA support" depends on RALINK && SOC_MT7621 diff --git a/drivers/staging/mt7621-dma/Makefile b/drivers/staging/mt7621-dma/Makefile index d3152d45cf45..c9e3e1619ab0 100644 --- a/drivers/staging/mt7621-dma/Makefile +++ b/drivers/staging/mt7621-dma/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_DMA_RALINK) += ralink-gdma.o obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o ccflags-y += -I$(srctree)/drivers/dma diff --git a/drivers/staging/mt7621-dma/ralink-gdma.c b/drivers/staging/mt7621-dma/ralink-gdma.c deleted file mode 100644 index d78042eba6dd..000000000000 --- a/drivers/staging/mt7621-dma/ralink-gdma.c +++ /dev/null @@ -1,932 +0,0 @@ -/* - * Copyright (C) 2013, Lars-Peter Clausen - * GDMA4740 DMAC support - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "virt-dma.h" - -#define GDMA_REG_SRC_ADDR(x) (0x00 + (x) * 0x10) -#define GDMA_REG_DST_ADDR(x) (0x04 + (x) * 0x10) - -#define GDMA_REG_CTRL0(x) (0x08 + (x) * 0x10) -#define GDMA_REG_CTRL0_TX_MASK 0xffff -#define GDMA_REG_CTRL0_TX_SHIFT 16 -#define GDMA_REG_CTRL0_CURR_MASK 0xff -#define GDMA_REG_CTRL0_CURR_SHIFT 8 -#define GDMA_REG_CTRL0_SRC_ADDR_FIXED BIT(7) -#define GDMA_REG_CTRL0_DST_ADDR_FIXED BIT(6) -#define GDMA_REG_CTRL0_BURST_MASK 0x7 -#define GDMA_REG_CTRL0_BURST_SHIFT 3 -#define GDMA_REG_CTRL0_DONE_INT BIT(2) -#define GDMA_REG_CTRL0_ENABLE BIT(1) -#define GDMA_REG_CTRL0_SW_MODE BIT(0) - -#define GDMA_REG_CTRL1(x) (0x0c + (x) * 0x10) -#define GDMA_REG_CTRL1_SEG_MASK 0xf -#define GDMA_REG_CTRL1_SEG_SHIFT 22 -#define GDMA_REG_CTRL1_REQ_MASK 0x3f -#define GDMA_REG_CTRL1_SRC_REQ_SHIFT 16 -#define GDMA_REG_CTRL1_DST_REQ_SHIFT 8 -#define GDMA_REG_CTRL1_NEXT_MASK 0x1f -#define GDMA_REG_CTRL1_NEXT_SHIFT 3 -#define GDMA_REG_CTRL1_COHERENT BIT(2) -#define GDMA_REG_CTRL1_FAIL BIT(1) -#define GDMA_REG_CTRL1_MASK BIT(0) - -#define GDMA_REG_UNMASK_INT 0x200 -#define GDMA_REG_DONE_INT 0x204 - -#define GDMA_REG_GCT 0x220 -#define GDMA_REG_GCT_CHAN_MASK 0x3 -#define GDMA_REG_GCT_CHAN_SHIFT 3 -#define GDMA_REG_GCT_VER_MASK 0x3 -#define GDMA_REG_GCT_VER_SHIFT 1 -#define GDMA_REG_GCT_ARBIT_RR BIT(0) - -#define GDMA_REG_REQSTS 0x2a0 -#define GDMA_REG_ACKSTS 0x2a4 -#define GDMA_REG_FINSTS 0x2a8 - -/* for RT305X gdma registers */ -#define GDMA_RT305X_CTRL0_REQ_MASK 0xf -#define GDMA_RT305X_CTRL0_SRC_REQ_SHIFT 12 -#define GDMA_RT305X_CTRL0_DST_REQ_SHIFT 8 - -#define GDMA_RT305X_CTRL1_FAIL BIT(4) -#define GDMA_RT305X_CTRL1_NEXT_MASK 0x7 -#define GDMA_RT305X_CTRL1_NEXT_SHIFT 1 - -#define GDMA_RT305X_STATUS_INT 0x80 -#define GDMA_RT305X_STATUS_SIGNAL 0x84 -#define GDMA_RT305X_GCT 0x88 - -/* for MT7621 gdma registers */ -#define GDMA_REG_PERF_START(x) (0x230 + (x) * 0x8) -#define GDMA_REG_PERF_END(x) (0x234 + (x) * 0x8) - -enum gdma_dma_transfer_size { - GDMA_TRANSFER_SIZE_4BYTE = 0, - GDMA_TRANSFER_SIZE_8BYTE = 1, - GDMA_TRANSFER_SIZE_16BYTE = 2, - GDMA_TRANSFER_SIZE_32BYTE = 3, - GDMA_TRANSFER_SIZE_64BYTE = 4, -}; - -struct gdma_dma_sg { - dma_addr_t src_addr; - dma_addr_t dst_addr; - u32 len; -}; - -struct gdma_dma_desc { - struct virt_dma_desc vdesc; - - enum dma_transfer_direction direction; - bool cyclic; - - u32 residue; - unsigned int num_sgs; - struct gdma_dma_sg sg[]; -}; - -struct gdma_dmaengine_chan { - struct virt_dma_chan vchan; - unsigned int id; - unsigned int slave_id; - - dma_addr_t fifo_addr; - enum gdma_dma_transfer_size burst_size; - - struct gdma_dma_desc *desc; - unsigned int next_sg; -}; - -struct gdma_dma_dev { - struct dma_device ddev; - struct device_dma_parameters dma_parms; - struct gdma_data *data; - void __iomem *base; - struct tasklet_struct task; - volatile unsigned long chan_issued; - atomic_t cnt; - - struct gdma_dmaengine_chan chan[]; -}; - -struct gdma_data { - int chancnt; - u32 done_int_reg; - void (*init)(struct gdma_dma_dev *dma_dev); - int (*start_transfer)(struct gdma_dmaengine_chan *chan); -}; - -static struct gdma_dma_dev *gdma_dma_chan_get_dev( - struct gdma_dmaengine_chan *chan) -{ - return container_of(chan->vchan.chan.device, struct gdma_dma_dev, - ddev); -} - -static struct gdma_dmaengine_chan *to_gdma_dma_chan(struct dma_chan *c) -{ - return container_of(c, struct gdma_dmaengine_chan, vchan.chan); -} - -static struct gdma_dma_desc *to_gdma_dma_desc(struct virt_dma_desc *vdesc) -{ - return container_of(vdesc, struct gdma_dma_desc, vdesc); -} - -static inline uint32_t gdma_dma_read(struct gdma_dma_dev *dma_dev, - unsigned int reg) -{ - return readl(dma_dev->base + reg); -} - -static inline void gdma_dma_write(struct gdma_dma_dev *dma_dev, - unsigned reg, uint32_t val) -{ - writel(val, dma_dev->base + reg); -} - -static struct gdma_dma_desc *gdma_dma_alloc_desc(unsigned int num_sgs) -{ - return kzalloc(sizeof(struct gdma_dma_desc) + - sizeof(struct gdma_dma_sg) * num_sgs, GFP_ATOMIC); -} - -static enum gdma_dma_transfer_size gdma_dma_maxburst(u32 maxburst) -{ - if (maxburst < 2) - return GDMA_TRANSFER_SIZE_4BYTE; - else if (maxburst < 4) - return GDMA_TRANSFER_SIZE_8BYTE; - else if (maxburst < 8) - return GDMA_TRANSFER_SIZE_16BYTE; - else if (maxburst < 16) - return GDMA_TRANSFER_SIZE_32BYTE; - else - return GDMA_TRANSFER_SIZE_64BYTE; -} - -static int gdma_dma_config(struct dma_chan *c, - struct dma_slave_config *config) -{ - struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); - struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); - - if (config->device_fc) { - dev_err(dma_dev->ddev.dev, "not support flow controller\n"); - return -EINVAL; - } - - switch (config->direction) { - case DMA_MEM_TO_DEV: - if (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { - dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); - return -EINVAL; - } - chan->slave_id = config->slave_id; - chan->fifo_addr = config->dst_addr; - chan->burst_size = gdma_dma_maxburst(config->dst_maxburst); - break; - case DMA_DEV_TO_MEM: - if (config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { - dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); - return -EINVAL; - } - chan->slave_id = config->slave_id; - chan->fifo_addr = config->src_addr; - chan->burst_size = gdma_dma_maxburst(config->src_maxburst); - break; - default: - dev_err(dma_dev->ddev.dev, "direction type %d error\n", - config->direction); - return -EINVAL; - } - - return 0; -} - -static int gdma_dma_terminate_all(struct dma_chan *c) -{ - struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); - struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); - unsigned long flags, timeout; - LIST_HEAD(head); - int i = 0; - - spin_lock_irqsave(&chan->vchan.lock, flags); - chan->desc = NULL; - clear_bit(chan->id, &dma_dev->chan_issued); - vchan_get_all_descriptors(&chan->vchan, &head); - spin_unlock_irqrestore(&chan->vchan.lock, flags); - - vchan_dma_desc_free_list(&chan->vchan, &head); - - /* wait dma transfer complete */ - timeout = jiffies + msecs_to_jiffies(5000); - while (gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)) & - GDMA_REG_CTRL0_ENABLE) { - if (time_after_eq(jiffies, timeout)) { - dev_err(dma_dev->ddev.dev, "chan %d wait timeout\n", - chan->id); - /* restore to init value */ - gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), 0); - break; - } - cpu_relax(); - i++; - } - - if (i) - dev_dbg(dma_dev->ddev.dev, "terminate chan %d loops %d\n", - chan->id, i); - - return 0; -} - -static void rt305x_dump_reg(struct gdma_dma_dev *dma_dev, int id) -{ - dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ - "ctr1 %08x, intr %08x, signal %08x\n", id, - gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), - gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), - gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), - gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), - gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_INT), - gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_SIGNAL)); -} - -static int rt305x_gdma_start_transfer(struct gdma_dmaengine_chan *chan) -{ - struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); - dma_addr_t src_addr, dst_addr; - struct gdma_dma_sg *sg; - uint32_t ctrl0, ctrl1; - - /* verify chan is already stopped */ - ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); - if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { - dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", - chan->id, ctrl0); - rt305x_dump_reg(dma_dev, chan->id); - return -EINVAL; - } - - sg = &chan->desc->sg[chan->next_sg]; - if (chan->desc->direction == DMA_MEM_TO_DEV) { - src_addr = sg->src_addr; - dst_addr = chan->fifo_addr; - ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED | \ - (8 << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ - (chan->slave_id << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); - } else if (chan->desc->direction == DMA_DEV_TO_MEM) { - src_addr = chan->fifo_addr; - dst_addr = sg->dst_addr; - ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED | \ - (chan->slave_id << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ - (8 << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); - } else if (chan->desc->direction == DMA_MEM_TO_MEM) { - /* - * TODO: memcpy function have bugs. sometime it will copy - * more 8 bytes data when using dmatest verify. - */ - src_addr = sg->src_addr; - dst_addr = sg->dst_addr; - ctrl0 = GDMA_REG_CTRL0_SW_MODE | \ - (8 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ - (8 << GDMA_REG_CTRL1_DST_REQ_SHIFT); - } else { - dev_err(dma_dev->ddev.dev, "direction type %d error\n", - chan->desc->direction); - return -EINVAL; - } - - ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ - (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ - GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; - ctrl1 = chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; - - chan->next_sg++; - gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); - gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); - gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); - - /* make sure next_sg is update */ - wmb(); - gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); - - return 0; -} - -static void rt3883_dump_reg(struct gdma_dma_dev *dma_dev, int id) -{ - dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ - "ctr1 %08x, unmask %08x, done %08x, " \ - "req %08x, ack %08x, fin %08x\n", id, - gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), - gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), - gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), - gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), - gdma_dma_read(dma_dev, GDMA_REG_UNMASK_INT), - gdma_dma_read(dma_dev, GDMA_REG_DONE_INT), - gdma_dma_read(dma_dev, GDMA_REG_REQSTS), - gdma_dma_read(dma_dev, GDMA_REG_ACKSTS), - gdma_dma_read(dma_dev, GDMA_REG_FINSTS)); -} - -static int rt3883_gdma_start_transfer(struct gdma_dmaengine_chan *chan) -{ - struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); - dma_addr_t src_addr, dst_addr; - struct gdma_dma_sg *sg; - uint32_t ctrl0, ctrl1; - - /* verify chan is already stopped */ - ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); - if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { - dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", - chan->id, ctrl0); - rt3883_dump_reg(dma_dev, chan->id); - return -EINVAL; - } - - sg = &chan->desc->sg[chan->next_sg]; - if (chan->desc->direction == DMA_MEM_TO_DEV) { - src_addr = sg->src_addr; - dst_addr = chan->fifo_addr; - ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED; - ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ - (chan->slave_id << GDMA_REG_CTRL1_DST_REQ_SHIFT); - } else if (chan->desc->direction == DMA_DEV_TO_MEM) { - src_addr = chan->fifo_addr; - dst_addr = sg->dst_addr; - ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED; - ctrl1 = (chan->slave_id << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ - (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ - GDMA_REG_CTRL1_COHERENT; - } else if (chan->desc->direction == DMA_MEM_TO_MEM) { - src_addr = sg->src_addr; - dst_addr = sg->dst_addr; - ctrl0 = GDMA_REG_CTRL0_SW_MODE; - ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ - (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ - GDMA_REG_CTRL1_COHERENT; - } else { - dev_err(dma_dev->ddev.dev, "direction type %d error\n", - chan->desc->direction); - return -EINVAL; - } - - ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ - (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ - GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; - ctrl1 |= chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; - - chan->next_sg++; - gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); - gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); - gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); - - /* make sure next_sg is update */ - wmb(); - gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); - - return 0; -} - -static inline int gdma_start_transfer(struct gdma_dma_dev *dma_dev, - struct gdma_dmaengine_chan *chan) -{ - return dma_dev->data->start_transfer(chan); -} - -static int gdma_next_desc(struct gdma_dmaengine_chan *chan) -{ - struct virt_dma_desc *vdesc; - - vdesc = vchan_next_desc(&chan->vchan); - if (!vdesc) { - chan->desc = NULL; - return 0; - } - chan->desc = to_gdma_dma_desc(vdesc); - chan->next_sg = 0; - - return 1; -} - -static void gdma_dma_chan_irq(struct gdma_dma_dev *dma_dev, - struct gdma_dmaengine_chan *chan) -{ - struct gdma_dma_desc *desc; - unsigned long flags; - int chan_issued; - - chan_issued = 0; - spin_lock_irqsave(&chan->vchan.lock, flags); - desc = chan->desc; - if (desc) { - if (desc->cyclic) { - vchan_cyclic_callback(&desc->vdesc); - if (chan->next_sg == desc->num_sgs) - chan->next_sg = 0; - chan_issued = 1; - } else { - desc->residue -= desc->sg[chan->next_sg - 1].len; - if (chan->next_sg == desc->num_sgs) { - list_del(&desc->vdesc.node); - vchan_cookie_complete(&desc->vdesc); - chan_issued = gdma_next_desc(chan); - } else { - chan_issued = 1; - } - } - } else { - dev_dbg(dma_dev->ddev.dev, "chan %d no desc to complete\n", - chan->id); - } - if (chan_issued) - set_bit(chan->id, &dma_dev->chan_issued); - spin_unlock_irqrestore(&chan->vchan.lock, flags); -} - -static irqreturn_t gdma_dma_irq(int irq, void *devid) -{ - struct gdma_dma_dev *dma_dev = devid; - u32 done, done_reg; - unsigned int i; - - done_reg = dma_dev->data->done_int_reg; - done = gdma_dma_read(dma_dev, done_reg); - if (unlikely(!done)) - return IRQ_NONE; - - /* clean done bits */ - gdma_dma_write(dma_dev, done_reg, done); - - i = 0; - while (done) { - if (done & 0x1) { - gdma_dma_chan_irq(dma_dev, &dma_dev->chan[i]); - atomic_dec(&dma_dev->cnt); - } - done >>= 1; - i++; - } - - /* start only have work to do */ - if (dma_dev->chan_issued) - tasklet_schedule(&dma_dev->task); - - return IRQ_HANDLED; -} - -static void gdma_dma_issue_pending(struct dma_chan *c) -{ - struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); - struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); - unsigned long flags; - - spin_lock_irqsave(&chan->vchan.lock, flags); - if (vchan_issue_pending(&chan->vchan) && !chan->desc) { - if (gdma_next_desc(chan)) { - set_bit(chan->id, &dma_dev->chan_issued); - tasklet_schedule(&dma_dev->task); - } else { - dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", - chan->id); - } - } - spin_unlock_irqrestore(&chan->vchan.lock, flags); -} - -static struct dma_async_tx_descriptor *gdma_dma_prep_slave_sg( - struct dma_chan *c, struct scatterlist *sgl, - unsigned int sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) -{ - struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); - struct gdma_dma_desc *desc; - struct scatterlist *sg; - unsigned int i; - - desc = gdma_dma_alloc_desc(sg_len); - if (!desc) { - dev_err(c->device->dev, "alloc sg decs error\n"); - return NULL; - } - desc->residue = 0; - - for_each_sg(sgl, sg, sg_len, i) { - if (direction == DMA_MEM_TO_DEV) { - desc->sg[i].src_addr = sg_dma_address(sg); - } else if (direction == DMA_DEV_TO_MEM) { - desc->sg[i].dst_addr = sg_dma_address(sg); - } else { - dev_err(c->device->dev, "direction type %d error\n", - direction); - goto free_desc; - } - - if (unlikely(sg_dma_len(sg) > GDMA_REG_CTRL0_TX_MASK)) { - dev_err(c->device->dev, "sg len too large %d\n", - sg_dma_len(sg)); - goto free_desc; - } - desc->sg[i].len = sg_dma_len(sg); - desc->residue += sg_dma_len(sg); - } - - desc->num_sgs = sg_len; - desc->direction = direction; - desc->cyclic = false; - - return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); - -free_desc: - kfree(desc); - return NULL; -} - -static struct dma_async_tx_descriptor *gdma_dma_prep_dma_memcpy( - struct dma_chan *c, dma_addr_t dest, dma_addr_t src, - size_t len, unsigned long flags) -{ - struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); - struct gdma_dma_desc *desc; - unsigned int num_periods, i; - size_t xfer_count; - - if (len <= 0) - return NULL; - - chan->burst_size = gdma_dma_maxburst(len >> 2); - - xfer_count = GDMA_REG_CTRL0_TX_MASK; - num_periods = DIV_ROUND_UP(len, xfer_count); - - desc = gdma_dma_alloc_desc(num_periods); - if (!desc) { - dev_err(c->device->dev, "alloc memcpy decs error\n"); - return NULL; - } - desc->residue = len; - - for (i = 0; i < num_periods; i++) { - desc->sg[i].src_addr = src; - desc->sg[i].dst_addr = dest; - if (len > xfer_count) - desc->sg[i].len = xfer_count; - else - desc->sg[i].len = len; - src += desc->sg[i].len; - dest += desc->sg[i].len; - len -= desc->sg[i].len; - } - - desc->num_sgs = num_periods; - desc->direction = DMA_MEM_TO_MEM; - desc->cyclic = false; - - return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -} - -static struct dma_async_tx_descriptor *gdma_dma_prep_dma_cyclic( - struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_transfer_direction direction, - unsigned long flags) -{ - struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); - struct gdma_dma_desc *desc; - unsigned int num_periods, i; - - if (buf_len % period_len) - return NULL; - - if (period_len > GDMA_REG_CTRL0_TX_MASK) { - dev_err(c->device->dev, "cyclic len too large %d\n", - period_len); - return NULL; - } - - num_periods = buf_len / period_len; - desc = gdma_dma_alloc_desc(num_periods); - if (!desc) { - dev_err(c->device->dev, "alloc cyclic decs error\n"); - return NULL; - } - desc->residue = buf_len; - - for (i = 0; i < num_periods; i++) { - if (direction == DMA_MEM_TO_DEV) { - desc->sg[i].src_addr = buf_addr; - } else if (direction == DMA_DEV_TO_MEM) { - desc->sg[i].dst_addr = buf_addr; - } else { - dev_err(c->device->dev, "direction type %d error\n", - direction); - goto free_desc; - } - desc->sg[i].len = period_len; - buf_addr += period_len; - } - - desc->num_sgs = num_periods; - desc->direction = direction; - desc->cyclic = true; - - return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); - -free_desc: - kfree(desc); - return NULL; -} - -static enum dma_status gdma_dma_tx_status(struct dma_chan *c, - dma_cookie_t cookie, - struct dma_tx_state *state) -{ - struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); - struct virt_dma_desc *vdesc; - enum dma_status status; - unsigned long flags; - struct gdma_dma_desc *desc; - - status = dma_cookie_status(c, cookie, state); - if (status == DMA_COMPLETE || !state) - return status; - - spin_lock_irqsave(&chan->vchan.lock, flags); - desc = chan->desc; - if (desc && (cookie == desc->vdesc.tx.cookie)) { - /* - * We never update edesc->residue in the cyclic case, so we - * can tell the remaining room to the end of the circular - * buffer. - */ - if (desc->cyclic) - state->residue = desc->residue - - ((chan->next_sg - 1) * desc->sg[0].len); - else - state->residue = desc->residue; - } else { - vdesc = vchan_find_desc(&chan->vchan, cookie); - if (vdesc) - state->residue = to_gdma_dma_desc(vdesc)->residue; - } - spin_unlock_irqrestore(&chan->vchan.lock, flags); - - dev_dbg(c->device->dev, "tx residue %d bytes\n", state->residue); - - return status; -} - -static void gdma_dma_free_chan_resources(struct dma_chan *c) -{ - vchan_free_chan_resources(to_virt_chan(c)); -} - -static void gdma_dma_desc_free(struct virt_dma_desc *vdesc) -{ - kfree(container_of(vdesc, struct gdma_dma_desc, vdesc)); -} - -static void gdma_dma_tasklet(unsigned long arg) -{ - struct gdma_dma_dev *dma_dev = (struct gdma_dma_dev *)arg; - struct gdma_dmaengine_chan *chan; - static unsigned int last_chan; - unsigned int i, chan_mask; - - /* record last chan to round robin all chans */ - i = last_chan; - chan_mask = dma_dev->data->chancnt - 1; - do { - /* - * on mt7621. when verify with dmatest with all - * channel is enable. we need to limit only two - * channel is working at the same time. otherwise the - * data will have problem. - */ - if (atomic_read(&dma_dev->cnt) >= 2) { - last_chan = i; - break; - } - - if (test_and_clear_bit(i, &dma_dev->chan_issued)) { - chan = &dma_dev->chan[i]; - if (chan->desc) { - atomic_inc(&dma_dev->cnt); - gdma_start_transfer(dma_dev, chan); - } else { - dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", chan->id); - } - if (!dma_dev->chan_issued) - break; - } - - i = (i + 1) & chan_mask; - } while (i != last_chan); -} - -static void rt305x_gdma_init(struct gdma_dma_dev *dma_dev) -{ - uint32_t gct; - - /* all chans round robin */ - gdma_dma_write(dma_dev, GDMA_RT305X_GCT, GDMA_REG_GCT_ARBIT_RR); - - gct = gdma_dma_read(dma_dev, GDMA_RT305X_GCT); - dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", - (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, - 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & - GDMA_REG_GCT_CHAN_MASK)); -} - -static void rt3883_gdma_init(struct gdma_dma_dev *dma_dev) -{ - uint32_t gct; - - /* all chans round robin */ - gdma_dma_write(dma_dev, GDMA_REG_GCT, GDMA_REG_GCT_ARBIT_RR); - - gct = gdma_dma_read(dma_dev, GDMA_REG_GCT); - dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", - (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, - 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & - GDMA_REG_GCT_CHAN_MASK)); -} - -static struct gdma_data rt305x_gdma_data = { - .chancnt = 8, - .done_int_reg = GDMA_RT305X_STATUS_INT, - .init = rt305x_gdma_init, - .start_transfer = rt305x_gdma_start_transfer, -}; - -static struct gdma_data rt3883_gdma_data = { - .chancnt = 16, - .done_int_reg = GDMA_REG_DONE_INT, - .init = rt3883_gdma_init, - .start_transfer = rt3883_gdma_start_transfer, -}; - -static const struct of_device_id gdma_of_match_table[] = { - { .compatible = "ralink,rt305x-gdma", .data = &rt305x_gdma_data }, - { .compatible = "ralink,rt3883-gdma", .data = &rt3883_gdma_data }, - { }, -}; - -static int gdma_dma_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct gdma_dmaengine_chan *chan; - struct gdma_dma_dev *dma_dev; - struct dma_device *dd; - unsigned int i; - struct resource *res; - int ret; - int irq; - void __iomem *base; - struct gdma_data *data; - - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - match = of_match_device(gdma_of_match_table, &pdev->dev); - if (!match) - return -EINVAL; - data = (struct gdma_data *) match->data; - - dma_dev = devm_kzalloc(&pdev->dev, - struct_size(dma_dev, chan, data->chancnt), - GFP_KERNEL); - if (!dma_dev) { - dev_err(&pdev->dev, "alloc dma device failed\n"); - return -EINVAL; - } - dma_dev->data = data; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - dma_dev->base = base; - tasklet_init(&dma_dev->task, gdma_dma_tasklet, (unsigned long)dma_dev); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); - return -EINVAL; - } - ret = devm_request_irq(&pdev->dev, irq, gdma_dma_irq, - 0, dev_name(&pdev->dev), dma_dev); - if (ret) { - dev_err(&pdev->dev, "failed to request irq\n"); - return ret; - } - - device_reset(&pdev->dev); - - dd = &dma_dev->ddev; - dma_cap_set(DMA_MEMCPY, dd->cap_mask); - dma_cap_set(DMA_SLAVE, dd->cap_mask); - dma_cap_set(DMA_CYCLIC, dd->cap_mask); - dd->device_free_chan_resources = gdma_dma_free_chan_resources; - dd->device_prep_dma_memcpy = gdma_dma_prep_dma_memcpy; - dd->device_prep_slave_sg = gdma_dma_prep_slave_sg; - dd->device_prep_dma_cyclic = gdma_dma_prep_dma_cyclic; - dd->device_config = gdma_dma_config; - dd->device_terminate_all = gdma_dma_terminate_all; - dd->device_tx_status = gdma_dma_tx_status; - dd->device_issue_pending = gdma_dma_issue_pending; - - dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); - dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); - dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); - dd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; - - dd->dev = &pdev->dev; - dd->dev->dma_parms = &dma_dev->dma_parms; - dma_set_max_seg_size(dd->dev, GDMA_REG_CTRL0_TX_MASK); - INIT_LIST_HEAD(&dd->channels); - - for (i = 0; i < data->chancnt; i++) { - chan = &dma_dev->chan[i]; - chan->id = i; - chan->vchan.desc_free = gdma_dma_desc_free; - vchan_init(&chan->vchan, dd); - } - - /* init hardware */ - data->init(dma_dev); - - ret = dma_async_device_register(dd); - if (ret) { - dev_err(&pdev->dev, "failed to register dma device\n"); - return ret; - } - - ret = of_dma_controller_register(pdev->dev.of_node, - of_dma_xlate_by_chan_id, dma_dev); - if (ret) { - dev_err(&pdev->dev, "failed to register of dma controller\n"); - goto err_unregister; - } - - platform_set_drvdata(pdev, dma_dev); - - return 0; - -err_unregister: - dma_async_device_unregister(dd); - return ret; -} - -static int gdma_dma_remove(struct platform_device *pdev) -{ - struct gdma_dma_dev *dma_dev = platform_get_drvdata(pdev); - - tasklet_kill(&dma_dev->task); - of_dma_controller_free(pdev->dev.of_node); - dma_async_device_unregister(&dma_dev->ddev); - - return 0; -} - -static struct platform_driver gdma_dma_driver = { - .probe = gdma_dma_probe, - .remove = gdma_dma_remove, - .driver = { - .name = "gdma-rt2880", - .of_match_table = gdma_of_match_table, - }, -}; -module_platform_driver(gdma_dma_driver); - -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("Ralink/MTK DMA driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/ralink-gdma/Kconfig b/drivers/staging/ralink-gdma/Kconfig new file mode 100644 index 000000000000..a12b2c672d48 --- /dev/null +++ b/drivers/staging/ralink-gdma/Kconfig @@ -0,0 +1,6 @@ +config DMA_RALINK + tristate "RALINK DMA support" + depends on RALINK && !SOC_RT288X + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + diff --git a/drivers/staging/ralink-gdma/Makefile b/drivers/staging/ralink-gdma/Makefile new file mode 100644 index 000000000000..5d917e0729bb --- /dev/null +++ b/drivers/staging/ralink-gdma/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DMA_RALINK) += ralink-gdma.o + +ccflags-y += -I$(srctree)/drivers/dma diff --git a/drivers/staging/ralink-gdma/ralink-gdma.c b/drivers/staging/ralink-gdma/ralink-gdma.c new file mode 100644 index 000000000000..d78042eba6dd --- /dev/null +++ b/drivers/staging/ralink-gdma/ralink-gdma.c @@ -0,0 +1,932 @@ +/* + * Copyright (C) 2013, Lars-Peter Clausen + * GDMA4740 DMAC support + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "virt-dma.h" + +#define GDMA_REG_SRC_ADDR(x) (0x00 + (x) * 0x10) +#define GDMA_REG_DST_ADDR(x) (0x04 + (x) * 0x10) + +#define GDMA_REG_CTRL0(x) (0x08 + (x) * 0x10) +#define GDMA_REG_CTRL0_TX_MASK 0xffff +#define GDMA_REG_CTRL0_TX_SHIFT 16 +#define GDMA_REG_CTRL0_CURR_MASK 0xff +#define GDMA_REG_CTRL0_CURR_SHIFT 8 +#define GDMA_REG_CTRL0_SRC_ADDR_FIXED BIT(7) +#define GDMA_REG_CTRL0_DST_ADDR_FIXED BIT(6) +#define GDMA_REG_CTRL0_BURST_MASK 0x7 +#define GDMA_REG_CTRL0_BURST_SHIFT 3 +#define GDMA_REG_CTRL0_DONE_INT BIT(2) +#define GDMA_REG_CTRL0_ENABLE BIT(1) +#define GDMA_REG_CTRL0_SW_MODE BIT(0) + +#define GDMA_REG_CTRL1(x) (0x0c + (x) * 0x10) +#define GDMA_REG_CTRL1_SEG_MASK 0xf +#define GDMA_REG_CTRL1_SEG_SHIFT 22 +#define GDMA_REG_CTRL1_REQ_MASK 0x3f +#define GDMA_REG_CTRL1_SRC_REQ_SHIFT 16 +#define GDMA_REG_CTRL1_DST_REQ_SHIFT 8 +#define GDMA_REG_CTRL1_NEXT_MASK 0x1f +#define GDMA_REG_CTRL1_NEXT_SHIFT 3 +#define GDMA_REG_CTRL1_COHERENT BIT(2) +#define GDMA_REG_CTRL1_FAIL BIT(1) +#define GDMA_REG_CTRL1_MASK BIT(0) + +#define GDMA_REG_UNMASK_INT 0x200 +#define GDMA_REG_DONE_INT 0x204 + +#define GDMA_REG_GCT 0x220 +#define GDMA_REG_GCT_CHAN_MASK 0x3 +#define GDMA_REG_GCT_CHAN_SHIFT 3 +#define GDMA_REG_GCT_VER_MASK 0x3 +#define GDMA_REG_GCT_VER_SHIFT 1 +#define GDMA_REG_GCT_ARBIT_RR BIT(0) + +#define GDMA_REG_REQSTS 0x2a0 +#define GDMA_REG_ACKSTS 0x2a4 +#define GDMA_REG_FINSTS 0x2a8 + +/* for RT305X gdma registers */ +#define GDMA_RT305X_CTRL0_REQ_MASK 0xf +#define GDMA_RT305X_CTRL0_SRC_REQ_SHIFT 12 +#define GDMA_RT305X_CTRL0_DST_REQ_SHIFT 8 + +#define GDMA_RT305X_CTRL1_FAIL BIT(4) +#define GDMA_RT305X_CTRL1_NEXT_MASK 0x7 +#define GDMA_RT305X_CTRL1_NEXT_SHIFT 1 + +#define GDMA_RT305X_STATUS_INT 0x80 +#define GDMA_RT305X_STATUS_SIGNAL 0x84 +#define GDMA_RT305X_GCT 0x88 + +/* for MT7621 gdma registers */ +#define GDMA_REG_PERF_START(x) (0x230 + (x) * 0x8) +#define GDMA_REG_PERF_END(x) (0x234 + (x) * 0x8) + +enum gdma_dma_transfer_size { + GDMA_TRANSFER_SIZE_4BYTE = 0, + GDMA_TRANSFER_SIZE_8BYTE = 1, + GDMA_TRANSFER_SIZE_16BYTE = 2, + GDMA_TRANSFER_SIZE_32BYTE = 3, + GDMA_TRANSFER_SIZE_64BYTE = 4, +}; + +struct gdma_dma_sg { + dma_addr_t src_addr; + dma_addr_t dst_addr; + u32 len; +}; + +struct gdma_dma_desc { + struct virt_dma_desc vdesc; + + enum dma_transfer_direction direction; + bool cyclic; + + u32 residue; + unsigned int num_sgs; + struct gdma_dma_sg sg[]; +}; + +struct gdma_dmaengine_chan { + struct virt_dma_chan vchan; + unsigned int id; + unsigned int slave_id; + + dma_addr_t fifo_addr; + enum gdma_dma_transfer_size burst_size; + + struct gdma_dma_desc *desc; + unsigned int next_sg; +}; + +struct gdma_dma_dev { + struct dma_device ddev; + struct device_dma_parameters dma_parms; + struct gdma_data *data; + void __iomem *base; + struct tasklet_struct task; + volatile unsigned long chan_issued; + atomic_t cnt; + + struct gdma_dmaengine_chan chan[]; +}; + +struct gdma_data { + int chancnt; + u32 done_int_reg; + void (*init)(struct gdma_dma_dev *dma_dev); + int (*start_transfer)(struct gdma_dmaengine_chan *chan); +}; + +static struct gdma_dma_dev *gdma_dma_chan_get_dev( + struct gdma_dmaengine_chan *chan) +{ + return container_of(chan->vchan.chan.device, struct gdma_dma_dev, + ddev); +} + +static struct gdma_dmaengine_chan *to_gdma_dma_chan(struct dma_chan *c) +{ + return container_of(c, struct gdma_dmaengine_chan, vchan.chan); +} + +static struct gdma_dma_desc *to_gdma_dma_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct gdma_dma_desc, vdesc); +} + +static inline uint32_t gdma_dma_read(struct gdma_dma_dev *dma_dev, + unsigned int reg) +{ + return readl(dma_dev->base + reg); +} + +static inline void gdma_dma_write(struct gdma_dma_dev *dma_dev, + unsigned reg, uint32_t val) +{ + writel(val, dma_dev->base + reg); +} + +static struct gdma_dma_desc *gdma_dma_alloc_desc(unsigned int num_sgs) +{ + return kzalloc(sizeof(struct gdma_dma_desc) + + sizeof(struct gdma_dma_sg) * num_sgs, GFP_ATOMIC); +} + +static enum gdma_dma_transfer_size gdma_dma_maxburst(u32 maxburst) +{ + if (maxburst < 2) + return GDMA_TRANSFER_SIZE_4BYTE; + else if (maxburst < 4) + return GDMA_TRANSFER_SIZE_8BYTE; + else if (maxburst < 8) + return GDMA_TRANSFER_SIZE_16BYTE; + else if (maxburst < 16) + return GDMA_TRANSFER_SIZE_32BYTE; + else + return GDMA_TRANSFER_SIZE_64BYTE; +} + +static int gdma_dma_config(struct dma_chan *c, + struct dma_slave_config *config) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + + if (config->device_fc) { + dev_err(dma_dev->ddev.dev, "not support flow controller\n"); + return -EINVAL; + } + + switch (config->direction) { + case DMA_MEM_TO_DEV: + if (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { + dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); + return -EINVAL; + } + chan->slave_id = config->slave_id; + chan->fifo_addr = config->dst_addr; + chan->burst_size = gdma_dma_maxburst(config->dst_maxburst); + break; + case DMA_DEV_TO_MEM: + if (config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { + dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); + return -EINVAL; + } + chan->slave_id = config->slave_id; + chan->fifo_addr = config->src_addr; + chan->burst_size = gdma_dma_maxburst(config->src_maxburst); + break; + default: + dev_err(dma_dev->ddev.dev, "direction type %d error\n", + config->direction); + return -EINVAL; + } + + return 0; +} + +static int gdma_dma_terminate_all(struct dma_chan *c) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + unsigned long flags, timeout; + LIST_HEAD(head); + int i = 0; + + spin_lock_irqsave(&chan->vchan.lock, flags); + chan->desc = NULL; + clear_bit(chan->id, &dma_dev->chan_issued); + vchan_get_all_descriptors(&chan->vchan, &head); + spin_unlock_irqrestore(&chan->vchan.lock, flags); + + vchan_dma_desc_free_list(&chan->vchan, &head); + + /* wait dma transfer complete */ + timeout = jiffies + msecs_to_jiffies(5000); + while (gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)) & + GDMA_REG_CTRL0_ENABLE) { + if (time_after_eq(jiffies, timeout)) { + dev_err(dma_dev->ddev.dev, "chan %d wait timeout\n", + chan->id); + /* restore to init value */ + gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), 0); + break; + } + cpu_relax(); + i++; + } + + if (i) + dev_dbg(dma_dev->ddev.dev, "terminate chan %d loops %d\n", + chan->id, i); + + return 0; +} + +static void rt305x_dump_reg(struct gdma_dma_dev *dma_dev, int id) +{ + dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ + "ctr1 %08x, intr %08x, signal %08x\n", id, + gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), + gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), + gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), + gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), + gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_INT), + gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_SIGNAL)); +} + +static int rt305x_gdma_start_transfer(struct gdma_dmaengine_chan *chan) +{ + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + dma_addr_t src_addr, dst_addr; + struct gdma_dma_sg *sg; + uint32_t ctrl0, ctrl1; + + /* verify chan is already stopped */ + ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); + if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { + dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", + chan->id, ctrl0); + rt305x_dump_reg(dma_dev, chan->id); + return -EINVAL; + } + + sg = &chan->desc->sg[chan->next_sg]; + if (chan->desc->direction == DMA_MEM_TO_DEV) { + src_addr = sg->src_addr; + dst_addr = chan->fifo_addr; + ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED | \ + (8 << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ + (chan->slave_id << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); + } else if (chan->desc->direction == DMA_DEV_TO_MEM) { + src_addr = chan->fifo_addr; + dst_addr = sg->dst_addr; + ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED | \ + (chan->slave_id << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ + (8 << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); + } else if (chan->desc->direction == DMA_MEM_TO_MEM) { + /* + * TODO: memcpy function have bugs. sometime it will copy + * more 8 bytes data when using dmatest verify. + */ + src_addr = sg->src_addr; + dst_addr = sg->dst_addr; + ctrl0 = GDMA_REG_CTRL0_SW_MODE | \ + (8 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ + (8 << GDMA_REG_CTRL1_DST_REQ_SHIFT); + } else { + dev_err(dma_dev->ddev.dev, "direction type %d error\n", + chan->desc->direction); + return -EINVAL; + } + + ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ + (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ + GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; + ctrl1 = chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; + + chan->next_sg++; + gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); + gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); + gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); + + /* make sure next_sg is update */ + wmb(); + gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); + + return 0; +} + +static void rt3883_dump_reg(struct gdma_dma_dev *dma_dev, int id) +{ + dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ + "ctr1 %08x, unmask %08x, done %08x, " \ + "req %08x, ack %08x, fin %08x\n", id, + gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), + gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), + gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), + gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), + gdma_dma_read(dma_dev, GDMA_REG_UNMASK_INT), + gdma_dma_read(dma_dev, GDMA_REG_DONE_INT), + gdma_dma_read(dma_dev, GDMA_REG_REQSTS), + gdma_dma_read(dma_dev, GDMA_REG_ACKSTS), + gdma_dma_read(dma_dev, GDMA_REG_FINSTS)); +} + +static int rt3883_gdma_start_transfer(struct gdma_dmaengine_chan *chan) +{ + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + dma_addr_t src_addr, dst_addr; + struct gdma_dma_sg *sg; + uint32_t ctrl0, ctrl1; + + /* verify chan is already stopped */ + ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); + if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { + dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", + chan->id, ctrl0); + rt3883_dump_reg(dma_dev, chan->id); + return -EINVAL; + } + + sg = &chan->desc->sg[chan->next_sg]; + if (chan->desc->direction == DMA_MEM_TO_DEV) { + src_addr = sg->src_addr; + dst_addr = chan->fifo_addr; + ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED; + ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ + (chan->slave_id << GDMA_REG_CTRL1_DST_REQ_SHIFT); + } else if (chan->desc->direction == DMA_DEV_TO_MEM) { + src_addr = chan->fifo_addr; + dst_addr = sg->dst_addr; + ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED; + ctrl1 = (chan->slave_id << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ + (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ + GDMA_REG_CTRL1_COHERENT; + } else if (chan->desc->direction == DMA_MEM_TO_MEM) { + src_addr = sg->src_addr; + dst_addr = sg->dst_addr; + ctrl0 = GDMA_REG_CTRL0_SW_MODE; + ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ + (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ + GDMA_REG_CTRL1_COHERENT; + } else { + dev_err(dma_dev->ddev.dev, "direction type %d error\n", + chan->desc->direction); + return -EINVAL; + } + + ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ + (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ + GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; + ctrl1 |= chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; + + chan->next_sg++; + gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); + gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); + gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); + + /* make sure next_sg is update */ + wmb(); + gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); + + return 0; +} + +static inline int gdma_start_transfer(struct gdma_dma_dev *dma_dev, + struct gdma_dmaengine_chan *chan) +{ + return dma_dev->data->start_transfer(chan); +} + +static int gdma_next_desc(struct gdma_dmaengine_chan *chan) +{ + struct virt_dma_desc *vdesc; + + vdesc = vchan_next_desc(&chan->vchan); + if (!vdesc) { + chan->desc = NULL; + return 0; + } + chan->desc = to_gdma_dma_desc(vdesc); + chan->next_sg = 0; + + return 1; +} + +static void gdma_dma_chan_irq(struct gdma_dma_dev *dma_dev, + struct gdma_dmaengine_chan *chan) +{ + struct gdma_dma_desc *desc; + unsigned long flags; + int chan_issued; + + chan_issued = 0; + spin_lock_irqsave(&chan->vchan.lock, flags); + desc = chan->desc; + if (desc) { + if (desc->cyclic) { + vchan_cyclic_callback(&desc->vdesc); + if (chan->next_sg == desc->num_sgs) + chan->next_sg = 0; + chan_issued = 1; + } else { + desc->residue -= desc->sg[chan->next_sg - 1].len; + if (chan->next_sg == desc->num_sgs) { + list_del(&desc->vdesc.node); + vchan_cookie_complete(&desc->vdesc); + chan_issued = gdma_next_desc(chan); + } else { + chan_issued = 1; + } + } + } else { + dev_dbg(dma_dev->ddev.dev, "chan %d no desc to complete\n", + chan->id); + } + if (chan_issued) + set_bit(chan->id, &dma_dev->chan_issued); + spin_unlock_irqrestore(&chan->vchan.lock, flags); +} + +static irqreturn_t gdma_dma_irq(int irq, void *devid) +{ + struct gdma_dma_dev *dma_dev = devid; + u32 done, done_reg; + unsigned int i; + + done_reg = dma_dev->data->done_int_reg; + done = gdma_dma_read(dma_dev, done_reg); + if (unlikely(!done)) + return IRQ_NONE; + + /* clean done bits */ + gdma_dma_write(dma_dev, done_reg, done); + + i = 0; + while (done) { + if (done & 0x1) { + gdma_dma_chan_irq(dma_dev, &dma_dev->chan[i]); + atomic_dec(&dma_dev->cnt); + } + done >>= 1; + i++; + } + + /* start only have work to do */ + if (dma_dev->chan_issued) + tasklet_schedule(&dma_dev->task); + + return IRQ_HANDLED; +} + +static void gdma_dma_issue_pending(struct dma_chan *c) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + unsigned long flags; + + spin_lock_irqsave(&chan->vchan.lock, flags); + if (vchan_issue_pending(&chan->vchan) && !chan->desc) { + if (gdma_next_desc(chan)) { + set_bit(chan->id, &dma_dev->chan_issued); + tasklet_schedule(&dma_dev->task); + } else { + dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", + chan->id); + } + } + spin_unlock_irqrestore(&chan->vchan.lock, flags); +} + +static struct dma_async_tx_descriptor *gdma_dma_prep_slave_sg( + struct dma_chan *c, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_desc *desc; + struct scatterlist *sg; + unsigned int i; + + desc = gdma_dma_alloc_desc(sg_len); + if (!desc) { + dev_err(c->device->dev, "alloc sg decs error\n"); + return NULL; + } + desc->residue = 0; + + for_each_sg(sgl, sg, sg_len, i) { + if (direction == DMA_MEM_TO_DEV) { + desc->sg[i].src_addr = sg_dma_address(sg); + } else if (direction == DMA_DEV_TO_MEM) { + desc->sg[i].dst_addr = sg_dma_address(sg); + } else { + dev_err(c->device->dev, "direction type %d error\n", + direction); + goto free_desc; + } + + if (unlikely(sg_dma_len(sg) > GDMA_REG_CTRL0_TX_MASK)) { + dev_err(c->device->dev, "sg len too large %d\n", + sg_dma_len(sg)); + goto free_desc; + } + desc->sg[i].len = sg_dma_len(sg); + desc->residue += sg_dma_len(sg); + } + + desc->num_sgs = sg_len; + desc->direction = direction; + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); + +free_desc: + kfree(desc); + return NULL; +} + +static struct dma_async_tx_descriptor *gdma_dma_prep_dma_memcpy( + struct dma_chan *c, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_desc *desc; + unsigned int num_periods, i; + size_t xfer_count; + + if (len <= 0) + return NULL; + + chan->burst_size = gdma_dma_maxburst(len >> 2); + + xfer_count = GDMA_REG_CTRL0_TX_MASK; + num_periods = DIV_ROUND_UP(len, xfer_count); + + desc = gdma_dma_alloc_desc(num_periods); + if (!desc) { + dev_err(c->device->dev, "alloc memcpy decs error\n"); + return NULL; + } + desc->residue = len; + + for (i = 0; i < num_periods; i++) { + desc->sg[i].src_addr = src; + desc->sg[i].dst_addr = dest; + if (len > xfer_count) + desc->sg[i].len = xfer_count; + else + desc->sg[i].len = len; + src += desc->sg[i].len; + dest += desc->sg[i].len; + len -= desc->sg[i].len; + } + + desc->num_sgs = num_periods; + desc->direction = DMA_MEM_TO_MEM; + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + +static struct dma_async_tx_descriptor *gdma_dma_prep_dma_cyclic( + struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_desc *desc; + unsigned int num_periods, i; + + if (buf_len % period_len) + return NULL; + + if (period_len > GDMA_REG_CTRL0_TX_MASK) { + dev_err(c->device->dev, "cyclic len too large %d\n", + period_len); + return NULL; + } + + num_periods = buf_len / period_len; + desc = gdma_dma_alloc_desc(num_periods); + if (!desc) { + dev_err(c->device->dev, "alloc cyclic decs error\n"); + return NULL; + } + desc->residue = buf_len; + + for (i = 0; i < num_periods; i++) { + if (direction == DMA_MEM_TO_DEV) { + desc->sg[i].src_addr = buf_addr; + } else if (direction == DMA_DEV_TO_MEM) { + desc->sg[i].dst_addr = buf_addr; + } else { + dev_err(c->device->dev, "direction type %d error\n", + direction); + goto free_desc; + } + desc->sg[i].len = period_len; + buf_addr += period_len; + } + + desc->num_sgs = num_periods; + desc->direction = direction; + desc->cyclic = true; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); + +free_desc: + kfree(desc); + return NULL; +} + +static enum dma_status gdma_dma_tx_status(struct dma_chan *c, + dma_cookie_t cookie, + struct dma_tx_state *state) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct virt_dma_desc *vdesc; + enum dma_status status; + unsigned long flags; + struct gdma_dma_desc *desc; + + status = dma_cookie_status(c, cookie, state); + if (status == DMA_COMPLETE || !state) + return status; + + spin_lock_irqsave(&chan->vchan.lock, flags); + desc = chan->desc; + if (desc && (cookie == desc->vdesc.tx.cookie)) { + /* + * We never update edesc->residue in the cyclic case, so we + * can tell the remaining room to the end of the circular + * buffer. + */ + if (desc->cyclic) + state->residue = desc->residue - + ((chan->next_sg - 1) * desc->sg[0].len); + else + state->residue = desc->residue; + } else { + vdesc = vchan_find_desc(&chan->vchan, cookie); + if (vdesc) + state->residue = to_gdma_dma_desc(vdesc)->residue; + } + spin_unlock_irqrestore(&chan->vchan.lock, flags); + + dev_dbg(c->device->dev, "tx residue %d bytes\n", state->residue); + + return status; +} + +static void gdma_dma_free_chan_resources(struct dma_chan *c) +{ + vchan_free_chan_resources(to_virt_chan(c)); +} + +static void gdma_dma_desc_free(struct virt_dma_desc *vdesc) +{ + kfree(container_of(vdesc, struct gdma_dma_desc, vdesc)); +} + +static void gdma_dma_tasklet(unsigned long arg) +{ + struct gdma_dma_dev *dma_dev = (struct gdma_dma_dev *)arg; + struct gdma_dmaengine_chan *chan; + static unsigned int last_chan; + unsigned int i, chan_mask; + + /* record last chan to round robin all chans */ + i = last_chan; + chan_mask = dma_dev->data->chancnt - 1; + do { + /* + * on mt7621. when verify with dmatest with all + * channel is enable. we need to limit only two + * channel is working at the same time. otherwise the + * data will have problem. + */ + if (atomic_read(&dma_dev->cnt) >= 2) { + last_chan = i; + break; + } + + if (test_and_clear_bit(i, &dma_dev->chan_issued)) { + chan = &dma_dev->chan[i]; + if (chan->desc) { + atomic_inc(&dma_dev->cnt); + gdma_start_transfer(dma_dev, chan); + } else { + dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", chan->id); + } + if (!dma_dev->chan_issued) + break; + } + + i = (i + 1) & chan_mask; + } while (i != last_chan); +} + +static void rt305x_gdma_init(struct gdma_dma_dev *dma_dev) +{ + uint32_t gct; + + /* all chans round robin */ + gdma_dma_write(dma_dev, GDMA_RT305X_GCT, GDMA_REG_GCT_ARBIT_RR); + + gct = gdma_dma_read(dma_dev, GDMA_RT305X_GCT); + dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", + (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, + 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & + GDMA_REG_GCT_CHAN_MASK)); +} + +static void rt3883_gdma_init(struct gdma_dma_dev *dma_dev) +{ + uint32_t gct; + + /* all chans round robin */ + gdma_dma_write(dma_dev, GDMA_REG_GCT, GDMA_REG_GCT_ARBIT_RR); + + gct = gdma_dma_read(dma_dev, GDMA_REG_GCT); + dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", + (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, + 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & + GDMA_REG_GCT_CHAN_MASK)); +} + +static struct gdma_data rt305x_gdma_data = { + .chancnt = 8, + .done_int_reg = GDMA_RT305X_STATUS_INT, + .init = rt305x_gdma_init, + .start_transfer = rt305x_gdma_start_transfer, +}; + +static struct gdma_data rt3883_gdma_data = { + .chancnt = 16, + .done_int_reg = GDMA_REG_DONE_INT, + .init = rt3883_gdma_init, + .start_transfer = rt3883_gdma_start_transfer, +}; + +static const struct of_device_id gdma_of_match_table[] = { + { .compatible = "ralink,rt305x-gdma", .data = &rt305x_gdma_data }, + { .compatible = "ralink,rt3883-gdma", .data = &rt3883_gdma_data }, + { }, +}; + +static int gdma_dma_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct gdma_dmaengine_chan *chan; + struct gdma_dma_dev *dma_dev; + struct dma_device *dd; + unsigned int i; + struct resource *res; + int ret; + int irq; + void __iomem *base; + struct gdma_data *data; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + match = of_match_device(gdma_of_match_table, &pdev->dev); + if (!match) + return -EINVAL; + data = (struct gdma_data *) match->data; + + dma_dev = devm_kzalloc(&pdev->dev, + struct_size(dma_dev, chan, data->chancnt), + GFP_KERNEL); + if (!dma_dev) { + dev_err(&pdev->dev, "alloc dma device failed\n"); + return -EINVAL; + } + dma_dev->data = data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + dma_dev->base = base; + tasklet_init(&dma_dev->task, gdma_dma_tasklet, (unsigned long)dma_dev); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + return -EINVAL; + } + ret = devm_request_irq(&pdev->dev, irq, gdma_dma_irq, + 0, dev_name(&pdev->dev), dma_dev); + if (ret) { + dev_err(&pdev->dev, "failed to request irq\n"); + return ret; + } + + device_reset(&pdev->dev); + + dd = &dma_dev->ddev; + dma_cap_set(DMA_MEMCPY, dd->cap_mask); + dma_cap_set(DMA_SLAVE, dd->cap_mask); + dma_cap_set(DMA_CYCLIC, dd->cap_mask); + dd->device_free_chan_resources = gdma_dma_free_chan_resources; + dd->device_prep_dma_memcpy = gdma_dma_prep_dma_memcpy; + dd->device_prep_slave_sg = gdma_dma_prep_slave_sg; + dd->device_prep_dma_cyclic = gdma_dma_prep_dma_cyclic; + dd->device_config = gdma_dma_config; + dd->device_terminate_all = gdma_dma_terminate_all; + dd->device_tx_status = gdma_dma_tx_status; + dd->device_issue_pending = gdma_dma_issue_pending; + + dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + dd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + + dd->dev = &pdev->dev; + dd->dev->dma_parms = &dma_dev->dma_parms; + dma_set_max_seg_size(dd->dev, GDMA_REG_CTRL0_TX_MASK); + INIT_LIST_HEAD(&dd->channels); + + for (i = 0; i < data->chancnt; i++) { + chan = &dma_dev->chan[i]; + chan->id = i; + chan->vchan.desc_free = gdma_dma_desc_free; + vchan_init(&chan->vchan, dd); + } + + /* init hardware */ + data->init(dma_dev); + + ret = dma_async_device_register(dd); + if (ret) { + dev_err(&pdev->dev, "failed to register dma device\n"); + return ret; + } + + ret = of_dma_controller_register(pdev->dev.of_node, + of_dma_xlate_by_chan_id, dma_dev); + if (ret) { + dev_err(&pdev->dev, "failed to register of dma controller\n"); + goto err_unregister; + } + + platform_set_drvdata(pdev, dma_dev); + + return 0; + +err_unregister: + dma_async_device_unregister(dd); + return ret; +} + +static int gdma_dma_remove(struct platform_device *pdev) +{ + struct gdma_dma_dev *dma_dev = platform_get_drvdata(pdev); + + tasklet_kill(&dma_dev->task); + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&dma_dev->ddev); + + return 0; +} + +static struct platform_driver gdma_dma_driver = { + .probe = gdma_dma_probe, + .remove = gdma_dma_remove, + .driver = { + .name = "gdma-rt2880", + .of_match_table = gdma_of_match_table, + }, +}; +module_platform_driver(gdma_dma_driver); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("Ralink/MTK DMA driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 82f1cebe64ea097a5851386ddee02b4ef45a2ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20B=C3=BCstgens?= Date: Tue, 15 Jan 2019 17:16:19 +0100 Subject: staging: rtl8188eu: Refactoring struct ndis_802_11_ssid from CamelCase to correct code style. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rtl8188eu uses CamelCase for many struct members. Refactors the ndis_802_11_ssid members Ssid and SsidLength to keep correct code style. Issue found by checkpatch. Signed-off-by: Florian Büstgens Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_ap.c | 8 ++--- drivers/staging/rtl8188eu/core/rtw_cmd.c | 12 +++---- drivers/staging/rtl8188eu/core/rtw_ieee80211.c | 6 ++-- drivers/staging/rtl8188eu/core/rtw_ioctl_set.c | 12 +++---- drivers/staging/rtl8188eu/core/rtw_mlme.c | 44 ++++++++++++------------- drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | 38 ++++++++++----------- drivers/staging/rtl8188eu/core/rtw_wlan_util.c | 18 +++++----- drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c | 2 +- drivers/staging/rtl8188eu/include/wlan_bssdef.h | 6 ++-- drivers/staging/rtl8188eu/os_dep/ioctl_linux.c | 34 +++++++++---------- drivers/staging/rtl8188eu/os_dep/os_intfs.c | 4 +-- drivers/staging/rtl8188eu/os_dep/rtw_android.c | 2 +- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 6 ++-- 13 files changed, 96 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 1f232ba6651c..94c9d9f8ee5c 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -82,7 +82,7 @@ static void update_BCNTIM(struct adapter *padapter) /* calculate head_len */ offset = _FIXED_IE_LENGTH_; - offset += pnetwork_mlmeext->Ssid.SsidLength + 2; + offset += pnetwork_mlmeext->ssid.ssid_length + 2; /* get supported rates len */ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, @@ -785,9 +785,9 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) /* SSID */ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->ie_length - _BEACON_IE_OFFSET_)); if (p && ie_len > 0) { - memset(&pbss_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); - memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len); - pbss_network->Ssid.SsidLength = ie_len; + memset(&pbss_network->ssid, 0, sizeof(struct ndis_802_11_ssid)); + memcpy(pbss_network->ssid.ssid, (p + 2), ie_len); + pbss_network->ssid.ssid_length = ie_len; } /* channel */ diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c index 407f65cf7150..83a2e58aef53 100644 --- a/drivers/staging/rtl8188eu/core/rtw_cmd.c +++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c @@ -263,7 +263,7 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int i; for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) { - if (ssid[i].SsidLength) { + if (ssid[i].ssid_length) { memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid)); psurveyPara->ssid_num++; } @@ -316,10 +316,10 @@ u8 rtw_createbss_cmd(struct adapter *padapter) led_control_8188eu(padapter, LED_CTL_START_TO_LINK); - if (pmlmepriv->assoc_ssid.SsidLength == 0) - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); + if (pmlmepriv->assoc_ssid.ssid_length == 0) + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.ssid)); else - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.ssid)); pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC); if (!pcmd) { @@ -358,10 +358,10 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) led_control_8188eu(padapter, LED_CTL_START_TO_LINK); - if (pmlmepriv->assoc_ssid.SsidLength == 0) + if (pmlmepriv->assoc_ssid.ssid_length == 0) RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n")); else - RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid)); + RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.ssid)); pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC); if (!pcmd) { diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c index 5c4ff81987bd..6ef67c25fdb7 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c @@ -234,7 +234,7 @@ int rtw_generate_ie(struct registry_priv *pregistrypriv) ie += 2; /* SSID */ - ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz); + ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->ssid.ssid_length, pdev_network->ssid.ssid, &sz); /* supported rates */ if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) { @@ -975,9 +975,9 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork) pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; } rtw_get_sec_ie(pnetwork->network.ies, pnetwork->network.ie_length, NULL, &rsn_len, NULL, &wpa_len); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.Ssid.Ssid)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.ssid.ssid)); RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_len =%d rsn_len =%d\n", __func__, wpa_len, rsn_len)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.Ssid.Ssid)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.ssid.ssid)); RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_len =%d rsn_len =%d\n", __func__, wpa_len, rsn_len)); if (rsn_len > 0) { diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c index 0b3eb0b40975..7d56767cdff6 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c @@ -77,7 +77,7 @@ u8 rtw_do_join(struct adapter *padapter) pibss = padapter->registrypriv.dev_network.MacAddress; - memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); + memcpy(&pdev_network->ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(padapter); @@ -208,7 +208,7 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) struct wlan_network *pnetwork = &pmlmepriv->cur_network; DBG_88E_LEVEL(_drv_info_, "set ssid [%s] fw_state=0x%08x\n", - ssid->Ssid, get_fwstate(pmlmepriv)); + ssid->ssid, get_fwstate(pmlmepriv)); if (!padapter->hw_init_completed) { RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, @@ -229,8 +229,8 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); - if (pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength && - !memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength)) { + if (pmlmepriv->assoc_ssid.ssid_length == ssid->ssid_length && + !memcmp(&pmlmepriv->assoc_ssid.ssid, ssid->ssid, ssid->ssid_length)) { if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("Set SSID is the same ssid, fw_state = 0x%08x\n", @@ -257,8 +257,8 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) } } else { RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set SSID not the same ssid\n")); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid =[%s] len = 0x%x\n", ssid->Ssid, (unsigned int)ssid->SsidLength)); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("assoc_ssid =[%s] len = 0x%x\n", pmlmepriv->assoc_ssid.Ssid, (unsigned int)pmlmepriv->assoc_ssid.SsidLength)); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid =[%s] len = 0x%x\n", ssid->ssid, (unsigned int)ssid->ssid_length)); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("assoc_ssid =[%s] len = 0x%x\n", pmlmepriv->assoc_ssid.ssid, (unsigned int)pmlmepriv->assoc_ssid.ssid_length)); rtw_disassoc_cmd(padapter, 0, true); diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index 714f7a70ed64..ca0cf8a86671 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -300,8 +300,8 @@ int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork) static int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b) { - return (a->Ssid.SsidLength == b->Ssid.SsidLength) && - !memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength); + return (a->ssid.ssid_length == b->ssid.ssid_length) && + !memcmp(a->ssid.ssid, b->ssid.ssid, a->ssid.ssid_length); } int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) @@ -315,9 +315,9 @@ int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) s_cap = le16_to_cpu(le_scap); d_cap = le16_to_cpu(le_dcap); - return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) && + return ((src->ssid.ssid_length == dst->ssid.ssid_length) && (!memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) && - (!memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) && + (!memcmp(src->ssid.ssid, dst->ssid.ssid, src->ssid.ssid_length)) && ((s_cap & WLAN_CAPABILITY_IBSS) == (d_cap & WLAN_CAPABILITY_IBSS)) && ((s_cap & WLAN_CAPABILITY_ESS) == @@ -558,7 +558,7 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) pnetwork = (struct wlan_bssid_ex *)pbuf; RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("%s, ssid=%s\n", __func__, pnetwork->Ssid.Ssid)); + ("%s, ssid=%s\n", __func__, pnetwork->ssid.ssid)); len = get_wlan_bssid_ex_sz(pnetwork); if (len > (sizeof(struct wlan_bssid_ex))) { @@ -587,8 +587,8 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) /* lock pmlmepriv->lock when you accessing network_q */ if (!check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { - if (pnetwork->Ssid.Ssid[0] == 0) - pnetwork->Ssid.SsidLength = 0; + if (pnetwork->ssid.ssid[0] == 0) + pnetwork->ssid.ssid_length = 0; rtw_add_network(adapter, pnetwork); } @@ -636,7 +636,7 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n")); - memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); + memcpy(&pdev_network->ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(adapter); rtw_generate_random_ibss(pibss); @@ -741,7 +741,7 @@ void rtw_free_assoc_resources_locked(struct adapter *adapter) RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n")); RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress=%pM ssid=%s\n", - tgt_network->network.MacAddress, tgt_network->network.Ssid.Ssid)); + tgt_network->network.MacAddress, tgt_network->network.ssid.ssid)); if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE)) { struct sta_info *psta; @@ -975,10 +975,10 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) rtw_get_encrypt_decrypt_from_registrypriv(adapter); - if (pmlmepriv->assoc_ssid.SsidLength == 0) + if (pmlmepriv->assoc_ssid.ssid_length == 0) RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ joinbss event call back for Any SSid\n")); else - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.ssid)); the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); @@ -1279,7 +1279,7 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); - memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); + memcpy(&pdev_network->ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(adapter); @@ -1422,9 +1422,9 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv } /* check ssid, if needed */ - if (pmlmepriv->assoc_ssid.SsidLength) { - if (competitor->network.Ssid.SsidLength != pmlmepriv->assoc_ssid.SsidLength || - memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength)) + if (pmlmepriv->assoc_ssid.ssid_length) { + if (competitor->network.ssid.ssid_length != pmlmepriv->assoc_ssid.ssid_length || + memcmp(competitor->network.ssid.ssid, pmlmepriv->assoc_ssid.ssid, pmlmepriv->assoc_ssid.ssid_length)) goto exit; } @@ -1445,8 +1445,8 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv if (updated) { DBG_88E("[by_bssid:%u][assoc_ssid:%s]new candidate: %s(%pM rssi:%d\n", pmlmepriv->assoc_by_bssid, - pmlmepriv->assoc_ssid.Ssid, - (*candidate)->network.Ssid.Ssid, + pmlmepriv->assoc_ssid.ssid, + (*candidate)->network.ssid.ssid, (*candidate)->network.MacAddress, (int)(*candidate)->network.Rssi); DBG_88E("[to_roaming:%u]\n", pmlmepriv->to_roaming); @@ -1493,7 +1493,7 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) goto exit; } else { DBG_88E("%s: candidate: %s(%pM ch:%u)\n", __func__, - candidate->network.Ssid.Ssid, candidate->network.MacAddress, + candidate->network.ssid.ssid, candidate->network.MacAddress, candidate->network.Configuration.DSConfig); } @@ -1772,7 +1772,7 @@ void rtw_init_registrypriv_dev_network(struct adapter *adapter) memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN); - memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(struct ndis_802_11_ssid)); + memcpy(&pdev_network->ssid, &pregistrypriv->ssid, sizeof(struct ndis_802_11_ssid)); pdev_network->Configuration.Length = sizeof(struct ndis_802_11_config); pdev_network->Configuration.BeaconPeriod = 100; @@ -2049,9 +2049,9 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) if (pmlmepriv->to_roaming > 0) { DBG_88E("roaming from %s(%pM length:%d\n", - pnetwork->network.Ssid.Ssid, pnetwork->network.MacAddress, - pnetwork->network.Ssid.SsidLength); - memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, sizeof(struct ndis_802_11_ssid)); + pnetwork->network.ssid.ssid, pnetwork->network.MacAddress, + pnetwork->network.ssid.ssid_length); + memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.ssid, sizeof(struct ndis_802_11_ssid)); pmlmepriv->assoc_by_bssid = false; diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index 7a36661ebbed..8f28aefbe6f9 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -402,7 +402,7 @@ static void issue_beacon(struct adapter *padapter, int timeout_ms) pattrib->pktlen += 2; /* SSID */ - pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->ssid.ssid_length, cur_network->ssid.ssid, &pattrib->pktlen); /* supported rates... */ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); @@ -562,7 +562,7 @@ static void issue_probersp(struct adapter *padapter, unsigned char *da) /* below for ad-hoc mode */ /* SSID */ - pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->ssid.ssid_length, cur_network->ssid.ssid, &pattrib->pktlen); /* supported rates... */ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); @@ -652,7 +652,7 @@ static int issue_probereq(struct adapter *padapter, pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); if (pssid) - pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &pattrib->pktlen); + pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->ssid_length, pssid->ssid, &pattrib->pktlen); else pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &pattrib->pktlen); @@ -1059,7 +1059,7 @@ static void issue_assocreq(struct adapter *padapter) pattrib->pktlen += 2; /* SSID */ - pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &pattrib->pktlen); + pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.ssid.ssid_length, pmlmeinfo->network.ssid.ssid, &pattrib->pktlen); /* supported rate & extended supported rate */ @@ -1929,7 +1929,7 @@ static void site_survey(struct adapter *padapter) int i; for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { - if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) { + if (pmlmeext->sitesurvey_res.ssid[i].ssid_length) { /* todo: to issue two probe req??? */ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), @@ -2071,10 +2071,10 @@ static u8 collect_bss_info(struct adapter *padapter, DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); return _FAIL; } - memcpy(bssid->Ssid.Ssid, (p + 2), len); - bssid->Ssid.SsidLength = len; + memcpy(bssid->ssid.ssid, (p + 2), len); + bssid->ssid.ssid_length = len; } else { - bssid->Ssid.SsidLength = 0; + bssid->ssid.ssid_length = 0; } memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); @@ -2526,7 +2526,7 @@ static unsigned int OnProbeReq(struct adapter *padapter, /* check (wildcard) SSID */ if (p) { - if ((ielen != 0 && memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) || + if ((ielen != 0 && memcmp((void *)(p+2), (void *)cur->ssid.ssid, cur->ssid.ssid_length)) || (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) return _SUCCESS; @@ -2975,10 +2975,10 @@ static unsigned int OnAssocReq(struct adapter *padapter, goto OnAssocReqFail; } else { /* check if ssid match */ - if (memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength)) + if (memcmp((void *)(p+2), cur->ssid.ssid, cur->ssid.ssid_length)) status = _STATS_FAILURE_; - if (ie_len != cur->Ssid.SsidLength) + if (ie_len != cur->ssid.ssid_length) status = _STATS_FAILURE_; } @@ -4658,7 +4658,7 @@ void linked_status_chk(struct adapter *padapter) } if (rx_chk != _SUCCESS) - issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1); + issue_probereq_ex(padapter, &pmlmeinfo->network.ssid, psta->hwaddr, 3, 1); if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) || rx_chk != _SUCCESS) { tx_chk = issue_nulldata(padapter, psta->hwaddr, 0, 3, 1); @@ -4674,15 +4674,15 @@ void linked_status_chk(struct adapter *padapter) if (rx_chk != _SUCCESS) { if (pmlmeext->retry == 0) { issue_probereq(padapter, - &pmlmeinfo->network.Ssid, + &pmlmeinfo->network.ssid, pmlmeinfo->network.MacAddress, false); issue_probereq(padapter, - &pmlmeinfo->network.Ssid, + &pmlmeinfo->network.ssid, pmlmeinfo->network.MacAddress, false); issue_probereq(padapter, - &pmlmeinfo->network.Ssid, + &pmlmeinfo->network.ssid, pmlmeinfo->network.MacAddress, false); } @@ -5136,11 +5136,11 @@ u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) pmlmeext->sitesurvey_res.channel_idx = 0; for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { - if (pparm->ssid[i].SsidLength) { - memcpy(pmlmeext->sitesurvey_res.ssid[i].Ssid, pparm->ssid[i].Ssid, IW_ESSID_MAX_SIZE); - pmlmeext->sitesurvey_res.ssid[i].SsidLength = pparm->ssid[i].SsidLength; + if (pparm->ssid[i].ssid_length) { + memcpy(pmlmeext->sitesurvey_res.ssid[i].ssid, pparm->ssid[i].ssid, IW_ESSID_MAX_SIZE); + pmlmeext->sitesurvey_res.ssid[i].ssid_length = pparm->ssid[i].ssid_length; } else { - pmlmeext->sitesurvey_res.ssid[i].SsidLength = 0; + pmlmeext->sitesurvey_res.ssid[i].ssid_length = 0; } } diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index 5f9c9de1f1da..4480deef95a1 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c @@ -935,17 +935,17 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) if (ssid_len > NDIS_802_11_LENGTH_SSID) ssid_len = 0; } - memcpy(bssid->Ssid.Ssid, (p + 2), ssid_len); - bssid->Ssid.SsidLength = ssid_len; + memcpy(bssid->ssid.ssid, (p + 2), ssid_len); + bssid->ssid.ssid_length = ssid_len; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " - "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid, - bssid->Ssid.SsidLength, cur_network->network.Ssid.Ssid, - cur_network->network.Ssid.SsidLength)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.ssid.ssid:%s bssid.ssid.ssid_length:%d " + "cur_network->network.ssid.ssid:%s len:%d\n", __func__, bssid->ssid.ssid, + bssid->ssid.ssid_length, cur_network->network.ssid.ssid, + cur_network->network.ssid.ssid_length)); - if (memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) || - bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) { - if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */ + if (memcmp(bssid->ssid.ssid, cur_network->network.ssid.ssid, 32) || + bssid->ssid.ssid_length != cur_network->network.ssid.ssid_length) { + if (bssid->ssid.ssid[0] != '\0' && bssid->ssid.ssid_length != 0) { /* not hidden ssid */ DBG_88E("%s(), SSID is not match return FAIL\n", __func__); goto _mismatch; } diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c index 7022221136f6..491d948e9f2a 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c @@ -257,7 +257,7 @@ static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength) /* below for ad-hoc mode */ /* SSID */ - pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->ssid.ssid_length, cur_network->ssid.ssid, &pktlen); /* supported rates... */ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); diff --git a/drivers/staging/rtl8188eu/include/wlan_bssdef.h b/drivers/staging/rtl8188eu/include/wlan_bssdef.h index 5e13a6ddf083..8462c9c2fd39 100644 --- a/drivers/staging/rtl8188eu/include/wlan_bssdef.h +++ b/drivers/staging/rtl8188eu/include/wlan_bssdef.h @@ -17,8 +17,8 @@ #define NDIS_802_11_RSSI long /* in dBm */ struct ndis_802_11_ssid { - u32 SsidLength; - u8 Ssid[32]; + u32 ssid_length; + u8 ssid[32]; }; enum NDIS_802_11_NETWORK_TYPE { @@ -180,7 +180,7 @@ struct wlan_bssid_ex { u32 Length; unsigned char MacAddress[ETH_ALEN]; u8 Reserved[2];/* 0]: IS beacon frame */ - struct ndis_802_11_ssid Ssid; + struct ndis_802_11_ssid ssid; u32 Privacy; NDIS_802_11_RSSI Rssi;/* in dBM,raw data ,get from PHY) */ enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index efaa1c779f4b..eaa4adb32a0d 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -116,8 +116,8 @@ static char *translate_scan(struct adapter *padapter, /* Add the ESSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - iwe.u.data.length = min_t(u16, pnetwork->network.Ssid.SsidLength, 32); - start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); + iwe.u.data.length = min_t(u16, pnetwork->network.ssid.ssid_length, 32); + start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.ssid.ssid); /* parsing HT_CAP_IE */ p = rtw_get_ie(&pnetwork->network.ies[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.ie_length-12); @@ -195,7 +195,7 @@ static char *translate_scan(struct adapter *padapter, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); + start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.ssid.ssid); /*Add basic and extended rates */ max_rate = 0; @@ -235,7 +235,7 @@ static char *translate_scan(struct adapter *padapter, u8 *p; rtw_get_sec_ie(pnetwork->network.ies, pnetwork->network.ie_length, rsn_ie, &rsn_len, wpa_ie, &wpa_len); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: ssid =%s\n", pnetwork->network.Ssid.Ssid)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: ssid =%s\n", pnetwork->network.ssid.ssid)); RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); if (wpa_len > 0) { @@ -1124,8 +1124,8 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, int len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE); - memcpy(ssid[0].Ssid, req->essid, len); - ssid[0].SsidLength = len; + memcpy(ssid[0].ssid, req->essid, len); + ssid[0].ssid_length = len; DBG_88E("IW_SCAN_THIS_ESSID, ssid =%s, len =%d\n", req->essid, req->essid_len); @@ -1158,8 +1158,8 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, } sec_len = *(pos++); len -= 1; if (sec_len > 0 && sec_len <= len) { - ssid[ssid_index].SsidLength = sec_len; - memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); + ssid[ssid_index].ssid_length = sec_len; + memcpy(ssid[ssid_index].ssid, pos, ssid[ssid_index].ssid_length); ssid_index++; } pos += sec_len; @@ -1310,9 +1310,9 @@ static int rtw_wx_set_essid(struct net_device *dev, DBG_88E("ssid =%s, len =%d\n", extra, wrqu->essid.length); memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid)); - ndis_ssid.SsidLength = len; - memcpy(ndis_ssid.Ssid, extra, len); - src_ssid = ndis_ssid.Ssid; + ndis_ssid.ssid_length = len; + memcpy(ndis_ssid.ssid, extra, len); + src_ssid = ndis_ssid.ssid; RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: ssid =[%s]\n", src_ssid)); spin_lock_bh(&queue->lock); @@ -1324,14 +1324,14 @@ static int rtw_wx_set_essid(struct net_device *dev, pmlmepriv->pscanned = pmlmepriv->pscanned->next; - dst_ssid = pnetwork->network.Ssid.Ssid; + dst_ssid = pnetwork->network.ssid.ssid; RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: dst_ssid =%s\n", - pnetwork->network.Ssid.Ssid)); + pnetwork->network.ssid.ssid)); - if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) && - (pnetwork->network.Ssid.SsidLength == ndis_ssid.SsidLength)) { + if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.ssid_length)) && + (pnetwork->network.ssid.ssid_length == ndis_ssid.ssid_length)) { RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: find match, set infra mode\n")); @@ -1378,8 +1378,8 @@ static int rtw_wx_get_essid(struct net_device *dev, if ((check_fwstate(pmlmepriv, _FW_LINKED)) || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) { - len = pcur_bss->Ssid.SsidLength; - memcpy(extra, pcur_bss->Ssid.Ssid, len); + len = pcur_bss->ssid.ssid_length; + memcpy(extra, pcur_bss->ssid.ssid, len); } else { len = 0; *extra = 0; diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index 6681383579ee..72fa446cb953 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -141,8 +141,8 @@ static void loadparam(struct adapter *padapter, struct net_device *pnetdev) GlobalDebugLevel = rtw_debug; - memcpy(registry_par->ssid.Ssid, "ANY", 3); - registry_par->ssid.SsidLength = 3; + memcpy(registry_par->ssid.ssid, "ANY", 3); + registry_par->ssid.ssid_length = 3; registry_par->channel = (u8)rtw_channel; registry_par->wireless_mode = (u8)rtw_wireless_mode; diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_android.c b/drivers/staging/rtl8188eu/os_dep/rtw_android.c index 2ea2af3286bc..7a090615dcbc 100644 --- a/drivers/staging/rtl8188eu/os_dep/rtw_android.c +++ b/drivers/staging/rtl8188eu/os_dep/rtw_android.c @@ -84,7 +84,7 @@ static int rtw_android_get_rssi(struct net_device *net, char *command, if (check_fwstate(pmlmepriv, _FW_LINKED)) { bytes_written += snprintf(&command[bytes_written], total_len, "%s rssi %d", - pcur_network->network.Ssid.Ssid, + pcur_network->network.ssid.ssid, padapter->recvpriv.rssi); } return bytes_written; diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 28cbd6b3d26c..1859ec3281e8 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -227,10 +227,10 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) check_fwstate(pmlmepriv, _FW_LINKED)) { pr_debug("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n", __func__, __LINE__, - pmlmepriv->cur_network.network.Ssid.Ssid, + pmlmepriv->cur_network.network.ssid.ssid, pmlmepriv->cur_network.network.MacAddress, - pmlmepriv->cur_network.network.Ssid.SsidLength, - pmlmepriv->assoc_ssid.SsidLength); + pmlmepriv->cur_network.network.ssid.ssid_length, + pmlmepriv->assoc_ssid.ssid_length); pmlmepriv->to_roaming = 1; } -- cgit v1.2.3 From 3d505147178b9f310008da4fad14743824d235a9 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Dec 2018 10:03:20 -0800 Subject: ice: Fix unused variable build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 2fd527b72bb6 ("net: ndo_bridge_setlink: Add extack") added a new parameter "extack" to ice_bridge_setlink but this parameter isn't used by the function. This results in a warning: unused parameter ‘extack’ [-Wunused-parameter]. Fix that by adding an "__always_unused" qualifier. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 8725569d11f0..90773b477d19 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3641,7 +3641,8 @@ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) */ static int ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, - u16 __always_unused flags, struct netlink_ext_ack *extack) + u16 __always_unused flags, + struct netlink_ext_ack __always_unused *extack) { struct ice_netdev_priv *np = netdev_priv(dev); struct ice_pf *pf = np->vsi->back; -- cgit v1.2.3 From ede63a8d45555d42c0e9564874568bbe9df3f8d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Jan 2019 10:45:50 +0100 Subject: drm: bridge: dw-hdmi: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c index cf3f0caf9c63..ed7af7518b52 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c @@ -614,7 +614,6 @@ static int snd_dw_hdmi_suspend(struct device *dev) struct snd_dw_hdmi *dw = dev_get_drvdata(dev); snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold); - snd_pcm_suspend_all(dw->pcm); return 0; } -- cgit v1.2.3 From f13c274da3896da705169409ad9b41df1ed84a33 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Jan 2019 09:55:23 -0800 Subject: ACPICA: Convert more ACPI errors to firmware errors ACPICA commit f3198c12f2df9d170b3da891a180b774cfe01e59 Also adds a new firmware error function, acpi_bios_exception. Link: https://github.com/acpica/acpica/commit/f3198c12 Signed-off-by: Bob Moore Signed-off-by: Erik Schmauss Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsopcode.c | 15 +++++++------- drivers/acpi/acpica/exoparg2.c | 8 ++++---- drivers/acpi/acpica/utxferror.c | 44 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 78f9de260d5f..a0b821031063 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -130,8 +130,8 @@ acpi_ds_init_buffer_field(u16 aml_opcode, /* Must have a valid (>0) bit count */ if (bit_count == 0) { - ACPI_ERROR((AE_INFO, - "Attempt to CreateField of length zero")); + ACPI_BIOS_ERROR((AE_INFO, + "Attempt to CreateField of length zero")); status = AE_AML_OPERAND_VALUE; goto cleanup; } @@ -194,12 +194,13 @@ acpi_ds_init_buffer_field(u16 aml_opcode, /* Entire field must fit within the current length of the buffer */ if ((bit_offset + bit_count) > (8 * (u32)buffer_desc->buffer.length)) { - ACPI_ERROR((AE_INFO, - "Field [%4.4s] at bit offset/length %u/%u " - "exceeds size of target Buffer (%u bits)", - acpi_ut_get_node_name(result_desc), bit_offset, - bit_count, 8 * (u32)buffer_desc->buffer.length)); status = AE_AML_BUFFER_LIMIT; + ACPI_BIOS_EXCEPTION((AE_INFO, status, + "Field [%4.4s] at bit offset/length %u/%u " + "exceeds size of target Buffer (%u bits)", + acpi_ut_get_node_name(result_desc), + bit_offset, bit_count, + 8 * (u32)buffer_desc->buffer.length)); goto cleanup; } diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 3a477566ba1b..e9509b1c9a3a 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -390,10 +390,10 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) /* Failure means that the Index was beyond the end of the object */ if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Index (0x%X%8.8X) is beyond end of object (length 0x%X)", - ACPI_FORMAT_UINT64(index), - (u32)length)); + ACPI_BIOS_EXCEPTION((AE_INFO, status, + "Index (0x%X%8.8X) is beyond end of object (length 0x%X)", + ACPI_FORMAT_UINT64(index), + (u32)length)); goto cleanup; } diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 6bb85d691fcb..a1ed7fced4db 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -185,6 +185,50 @@ acpi_bios_error(const char *module_name, ACPI_EXPORT_SYMBOL(acpi_bios_error) +/******************************************************************************* + * + * FUNCTION: acpi_bios_exception + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * status - Status value to be decoded/formatted + * format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print an "ACPI Firmware Error" message with module/line/version + * info as well as decoded acpi_status. + * + ******************************************************************************/ +void ACPI_INTERNAL_VAR_XFACE +acpi_bios_exception(const char *module_name, + u32 line_number, + acpi_status status, const char *format, ...) +{ + va_list arg_list; + + ACPI_MSG_REDIRECT_BEGIN; + + /* For AE_OK, just print the message */ + + if (ACPI_SUCCESS(status)) { + acpi_os_printf(ACPI_MSG_BIOS_ERROR); + + } else { + acpi_os_printf(ACPI_MSG_BIOS_ERROR "%s, ", + acpi_format_exception(status)); + } + + va_start(arg_list, format); + acpi_os_vprintf(format, arg_list); + ACPI_MSG_SUFFIX; + va_end(arg_list); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL(acpi_bios_exception) + /******************************************************************************* * * FUNCTION: acpi_bios_warning -- cgit v1.2.3 From 894b5cc535b81d14e721b2c30fd4a238efce7f41 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Jan 2019 09:55:24 -0800 Subject: ACPICA: acpiexec: Add option to dump extra info for memory leaks ACPICA commit f77565e28b90ee7e06f53a474183ef72300c3574 Dump entire object/buffer for any memory leaks detected by the object/cache tracking mechanism. Link: https://github.com/acpica/acpica/commit/f77565e2 Signed-off-by: Bob Moore Signed-off-by: Erik Schmauss Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 1 + drivers/acpi/acpica/utdecode.c | 10 +++++----- drivers/acpi/acpica/uttrack.c | 12 ++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 87d6eb01beaf..7a0aeb70ec34 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -164,6 +164,7 @@ ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_global_list); ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_ns_node_list); ACPI_GLOBAL(u8, acpi_gbl_display_final_mem_stats); ACPI_GLOBAL(u8, acpi_gbl_disable_mem_tracking); +ACPI_GLOBAL(u8, acpi_gbl_verbose_leak_dump); #endif /***************************************************************************** diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index dad02b821e19..d0a375c3f4e2 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -284,7 +284,7 @@ const char *acpi_ut_get_node_name(void *object) static const char *acpi_gbl_desc_type_names[] = { /* 00 */ "Not a Descriptor", - /* 01 */ "Cached", + /* 01 */ "Cached Object", /* 02 */ "State-Generic", /* 03 */ "State-Update", /* 04 */ "State-Package", @@ -295,10 +295,10 @@ static const char *acpi_gbl_desc_type_names[] = { /* 09 */ "State-Result", /* 10 */ "State-Notify", /* 11 */ "State-Thread", - /* 12 */ "Walk", - /* 13 */ "Parser", - /* 14 */ "Operand", - /* 15 */ "Node" + /* 12 */ "Tree Walk State", + /* 13 */ "Parse Tree Op", + /* 14 */ "Operand Object", + /* 15 */ "Namespace Node" }; const char *acpi_ut_get_descriptor_name(void *object) diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 016a6621cc6f..f6b55e2482ee 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -588,6 +588,18 @@ void acpi_ut_dump_allocations(u32 component, const char *module) acpi_ut_get_descriptor_name (descriptor)); + /* Optional object hex dump */ + + if (acpi_gbl_verbose_leak_dump) { + acpi_os_printf("\n"); + acpi_ut_dump_buffer((u8 *) + descriptor, + element-> + size, + DB_BYTE_DISPLAY, + 0); + } + /* Validate the descriptor type using Type field and length */ descriptor_type = 0; /* Not a valid descriptor type */ -- cgit v1.2.3 From 840c02ca2215af648c781ae680d93d8aecd083b7 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Jan 2019 09:55:25 -0800 Subject: ACPICA: All acpica: Update copyrights to 2019 ACPICA commit 62f4f98e941d86e41969bf2ab5a93b8dc94dc49e The update includes userspace tool signons. Link: https://github.com/acpica/acpica/commit/62f4f98e Signed-off-by: Bob Moore Signed-off-by: Erik Schmauss Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acapps.h | 4 ++-- drivers/acpi/acpica/accommon.h | 2 +- drivers/acpi/acpica/acconvert.h | 2 +- drivers/acpi/acpica/acdebug.h | 2 +- drivers/acpi/acpica/acdispat.h | 2 +- drivers/acpi/acpica/acevents.h | 2 +- drivers/acpi/acpica/acglobal.h | 2 +- drivers/acpi/acpica/achware.h | 2 +- drivers/acpi/acpica/acinterp.h | 2 +- drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/acmacros.h | 2 +- drivers/acpi/acpica/acnamesp.h | 2 +- drivers/acpi/acpica/acobject.h | 2 +- drivers/acpi/acpica/acopcode.h | 2 +- drivers/acpi/acpica/acparser.h | 2 +- drivers/acpi/acpica/acpredef.h | 2 +- drivers/acpi/acpica/acresrc.h | 2 +- drivers/acpi/acpica/acstruct.h | 2 +- drivers/acpi/acpica/actables.h | 2 +- drivers/acpi/acpica/acutils.h | 2 +- drivers/acpi/acpica/amlcode.h | 2 +- drivers/acpi/acpica/amlresrc.h | 2 +- drivers/acpi/acpica/dbhistry.c | 2 +- drivers/acpi/acpica/dsargs.c | 2 +- drivers/acpi/acpica/dscontrol.c | 2 +- drivers/acpi/acpica/dsdebug.c | 2 +- drivers/acpi/acpica/dsfield.c | 2 +- drivers/acpi/acpica/dsinit.c | 2 +- drivers/acpi/acpica/dsmethod.c | 2 +- drivers/acpi/acpica/dsobject.c | 2 +- drivers/acpi/acpica/dsopcode.c | 2 +- drivers/acpi/acpica/dspkginit.c | 2 +- drivers/acpi/acpica/dswexec.c | 2 +- drivers/acpi/acpica/dswload.c | 2 +- drivers/acpi/acpica/dswload2.c | 2 +- drivers/acpi/acpica/dswscope.c | 2 +- drivers/acpi/acpica/dswstate.c | 2 +- drivers/acpi/acpica/evevent.c | 2 +- drivers/acpi/acpica/evglock.c | 2 +- drivers/acpi/acpica/evgpe.c | 2 +- drivers/acpi/acpica/evgpeblk.c | 2 +- drivers/acpi/acpica/evgpeinit.c | 2 +- drivers/acpi/acpica/evgpeutil.c | 2 +- drivers/acpi/acpica/evhandler.c | 2 +- drivers/acpi/acpica/evmisc.c | 2 +- drivers/acpi/acpica/evregion.c | 2 +- drivers/acpi/acpica/evrgnini.c | 2 +- drivers/acpi/acpica/evxface.c | 2 +- drivers/acpi/acpica/evxfevnt.c | 2 +- drivers/acpi/acpica/evxfgpe.c | 2 +- drivers/acpi/acpica/evxfregn.c | 2 +- drivers/acpi/acpica/exconcat.c | 2 +- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/exconvrt.c | 2 +- drivers/acpi/acpica/excreate.c | 2 +- drivers/acpi/acpica/exdebug.c | 2 +- drivers/acpi/acpica/exdump.c | 2 +- drivers/acpi/acpica/exfield.c | 2 +- drivers/acpi/acpica/exfldio.c | 2 +- drivers/acpi/acpica/exmisc.c | 2 +- drivers/acpi/acpica/exmutex.c | 2 +- drivers/acpi/acpica/exnames.c | 2 +- drivers/acpi/acpica/exoparg1.c | 2 +- drivers/acpi/acpica/exoparg2.c | 2 +- drivers/acpi/acpica/exoparg3.c | 2 +- drivers/acpi/acpica/exoparg6.c | 2 +- drivers/acpi/acpica/exprep.c | 2 +- drivers/acpi/acpica/exregion.c | 2 +- drivers/acpi/acpica/exresnte.c | 2 +- drivers/acpi/acpica/exresolv.c | 2 +- drivers/acpi/acpica/exresop.c | 2 +- drivers/acpi/acpica/exserial.c | 2 +- drivers/acpi/acpica/exstore.c | 2 +- drivers/acpi/acpica/exstoren.c | 2 +- drivers/acpi/acpica/exstorob.c | 2 +- drivers/acpi/acpica/exsystem.c | 2 +- drivers/acpi/acpica/extrace.c | 2 +- drivers/acpi/acpica/exutils.c | 2 +- drivers/acpi/acpica/hwacpi.c | 2 +- drivers/acpi/acpica/hwesleep.c | 2 +- drivers/acpi/acpica/hwgpe.c | 2 +- drivers/acpi/acpica/hwsleep.c | 2 +- drivers/acpi/acpica/hwtimer.c | 2 +- drivers/acpi/acpica/hwvalid.c | 2 +- drivers/acpi/acpica/hwxface.c | 2 +- drivers/acpi/acpica/hwxfsleep.c | 2 +- drivers/acpi/acpica/nsarguments.c | 2 +- drivers/acpi/acpica/nsconvert.c | 2 +- drivers/acpi/acpica/nsdump.c | 2 +- drivers/acpi/acpica/nsdumpdv.c | 2 +- drivers/acpi/acpica/nsinit.c | 2 +- drivers/acpi/acpica/nsload.c | 2 +- drivers/acpi/acpica/nsparse.c | 2 +- drivers/acpi/acpica/nspredef.c | 2 +- drivers/acpi/acpica/nsprepkg.c | 2 +- drivers/acpi/acpica/nsrepair.c | 2 +- drivers/acpi/acpica/nsrepair2.c | 2 +- drivers/acpi/acpica/nsutils.c | 2 +- drivers/acpi/acpica/nswalk.c | 2 +- drivers/acpi/acpica/nsxfname.c | 2 +- drivers/acpi/acpica/psargs.c | 2 +- drivers/acpi/acpica/psloop.c | 2 +- drivers/acpi/acpica/psobject.c | 2 +- drivers/acpi/acpica/psopcode.c | 2 +- drivers/acpi/acpica/psopinfo.c | 2 +- drivers/acpi/acpica/psparse.c | 2 +- drivers/acpi/acpica/psscope.c | 2 +- drivers/acpi/acpica/pstree.c | 2 +- drivers/acpi/acpica/psutils.c | 2 +- drivers/acpi/acpica/pswalk.c | 2 +- drivers/acpi/acpica/psxface.c | 2 +- drivers/acpi/acpica/tbdata.c | 2 +- drivers/acpi/acpica/tbfadt.c | 2 +- drivers/acpi/acpica/tbfind.c | 2 +- drivers/acpi/acpica/tbinstal.c | 2 +- drivers/acpi/acpica/tbprint.c | 2 +- drivers/acpi/acpica/tbutils.c | 2 +- drivers/acpi/acpica/tbxface.c | 2 +- drivers/acpi/acpica/tbxfload.c | 2 +- drivers/acpi/acpica/tbxfroot.c | 2 +- drivers/acpi/acpica/utaddress.c | 2 +- drivers/acpi/acpica/utalloc.c | 2 +- drivers/acpi/acpica/utascii.c | 2 +- drivers/acpi/acpica/utbuffer.c | 2 +- drivers/acpi/acpica/utcache.c | 2 +- drivers/acpi/acpica/utcopy.c | 2 +- drivers/acpi/acpica/utdebug.c | 2 +- drivers/acpi/acpica/utdecode.c | 2 +- drivers/acpi/acpica/uteval.c | 2 +- drivers/acpi/acpica/utglobal.c | 2 +- drivers/acpi/acpica/uthex.c | 2 +- drivers/acpi/acpica/utids.c | 2 +- drivers/acpi/acpica/utinit.c | 2 +- drivers/acpi/acpica/utlock.c | 2 +- drivers/acpi/acpica/utobject.c | 2 +- drivers/acpi/acpica/utosi.c | 2 +- drivers/acpi/acpica/utpredef.c | 2 +- drivers/acpi/acpica/utprint.c | 2 +- drivers/acpi/acpica/uttrack.c | 2 +- drivers/acpi/acpica/utuuid.c | 2 +- drivers/acpi/acpica/utxface.c | 2 +- drivers/acpi/acpica/utxfinit.c | 2 +- 142 files changed, 143 insertions(+), 143 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 5a9c2febc0fb..863ade9add6d 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -3,7 +3,7 @@ * * Module Name: acapps - common include for ACPI applications/tools * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ @@ -17,7 +17,7 @@ /* Common info for tool signons */ #define ACPICA_NAME "Intel ACPI Component Architecture" -#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2018 Intel Corporation" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2019 Intel Corporation" #if ACPI_MACHINE_WIDTH == 64 #define ACPI_WIDTH " (64-bit version)" diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index 8bc935977d8e..54f81eac7ec9 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -3,7 +3,7 @@ * * Name: accommon.h - Common include files for generation of ACPICA source * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acconvert.h b/drivers/acpi/acpica/acconvert.h index 4ebe18826646..d5478cd4a857 100644 --- a/drivers/acpi/acpica/acconvert.h +++ b/drivers/acpi/acpica/acconvert.h @@ -3,7 +3,7 @@ * * Module Name: acapps - common include for ACPI applications/tools * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 57d9495e5933..3a339045b1bf 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -3,7 +3,7 @@ * * Name: acdebug.h - ACPI/AML debugger * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index e577f3a40e6a..82f81501566b 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -3,7 +3,7 @@ * * Name: acdispat.h - dispatcher (parser to interpreter interface) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index b412aa909907..831660179662 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -3,7 +3,7 @@ * * Name: acevents.h - Event subcomponent prototypes and defines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 7a0aeb70ec34..d056a1845613 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -3,7 +3,7 @@ * * Name: acglobal.h - Declarations for global variables * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index ef99e2fc37f8..bcf8f7501db7 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -3,7 +3,7 @@ * * Name: achware.h -- hardware specific interfaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index c5b2be0b6613..20706adbc148 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -3,7 +3,7 @@ * * Name: acinterp.h - Interpreter subcomponent prototypes and defines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 99b0da899109..18ec6627d674 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -3,7 +3,7 @@ * * Name: aclocal.h - Internal data types used across the ACPI subsystem * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index de52cd6e868a..99131cd4e389 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -3,7 +3,7 @@ * * Name: acmacros.h - C macros for the entire subsystem. * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 9bd25f36c608..39812fc4386a 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -3,7 +3,7 @@ * * Name: acnamesp.h - Namespace subcomponent prototypes and defines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index ac992b6ebce9..0edf8fca7567 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -3,7 +3,7 @@ * * Name: acobject.h - Definition of union acpi_operand_object (Internal object only) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index 818eba413614..9d78134428e3 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -3,7 +3,7 @@ * * Name: acopcode.h - AML opcode information for the AML parser and interpreter * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index ab48196ae55e..6e32c97cba6c 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -3,7 +3,7 @@ * * Module Name: acparser.h - AML Parser subcomponent prototypes and defines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index d31bb04facb6..cc96b40032b3 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -3,7 +3,7 @@ * * Name: acpredef - Information table for ACPI predefined methods and objects * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index 59ae8b1a6e40..422cd8f2b92e 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -3,7 +3,7 @@ * * Name: acresrc.h - Resource Manager function prototypes * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 14be32961b4c..8a4e6b4aaf2c 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -3,7 +3,7 @@ * * Name: acstruct.h - Internal structs * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 12fac33ce77e..dfbf1dbd4033 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -3,7 +3,7 @@ * * Name: actables.h - ACPI table management * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 3374d41582b5..9022537567e9 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -3,7 +3,7 @@ * * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 6c05355447c1..49e412edd7c6 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -5,7 +5,7 @@ * Declarations and definitions contained herein are derived * directly from the ACPI specification. * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index cdb590176e9d..7c3bd4ab60fc 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -3,7 +3,7 @@ * * Module Name: amlresrc.h - AML resource descriptors * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dbhistry.c b/drivers/acpi/acpica/dbhistry.c index b0b9a26c7db5..7809bd94a18d 100644 --- a/drivers/acpi/acpica/dbhistry.c +++ b/drivers/acpi/acpica/dbhistry.c @@ -3,7 +3,7 @@ * * Module Name: dbhistry - debugger HISTORY command * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 6b15625e8099..85b34d02233e 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -4,7 +4,7 @@ * Module Name: dsargs - Support for execution of dynamic arguments for static * objects (regions, fields, buffer fields, etc.) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 0da96268deb5..4847f89c678c 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -4,7 +4,7 @@ * Module Name: dscontrol - Support for execution control opcodes - * if/else/while/return * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 9d33f0bb2885..0d3e1ced1f57 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -3,7 +3,7 @@ * * Module Name: dsdebug - Parser/Interpreter interface - debugging * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 30fe89545d6a..d51216c9d891 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -3,7 +3,7 @@ * * Module Name: dsfield - Dispatcher field routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index e8de1b0ce2f5..a4a24ffe5fae 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -3,7 +3,7 @@ * * Module Name: dsinit - Object initialization namespace walk * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index c1a4d02fafd5..f59b4d944f7f 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -3,7 +3,7 @@ * * Module Name: dsmethod - Parser/Interpreter interface - control method parsing * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 6a9cc613adaa..179129a2deb1 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -3,7 +3,7 @@ * * Module Name: dsobject - Dispatcher object management routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index a0b821031063..cab14713e591 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -3,7 +3,7 @@ * * Module Name: dsopcode - Dispatcher support for regions and fields * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dspkginit.c b/drivers/acpi/acpica/dspkginit.c index 584853385268..997faa10f615 100644 --- a/drivers/acpi/acpica/dspkginit.c +++ b/drivers/acpi/acpica/dspkginit.c @@ -3,7 +3,7 @@ * * Module Name: dspkginit - Completion of deferred package initialization * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index 1504b93cc5f4..d75aae304595 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -4,7 +4,7 @@ * Module Name: dswexec - Dispatcher method execution callbacks; * dispatch to interpreter. * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index e2ef09643d50..c88fd31208a5 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -3,7 +3,7 @@ * * Module Name: dswload - Dispatcher first pass namespace load callbacks * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 9a309f5c4de8..98cdc24c640f 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -3,7 +3,7 @@ * * Module Name: dswload2 - Dispatcher second pass namespace load callbacks * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index 7592176a8fa2..39acf7b286da 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -3,7 +3,7 @@ * * Module Name: dswscope - Scope stack manipulation * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 4c1ec202d5ab..de79f835a373 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -3,7 +3,7 @@ * * Module Name: dswstate - Dispatcher parse tree walk management routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index b3d07cc14d75..9e2f5a05c066 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -3,7 +3,7 @@ * * Module Name: evevent - Fixed Event handling and dispatch * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c index 1b8a662a14a9..5c77bee5d31f 100644 --- a/drivers/acpi/acpica/evglock.c +++ b/drivers/acpi/acpica/evglock.c @@ -3,7 +3,7 @@ * * Module Name: evglock - Global Lock support * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index e10fec99a182..a5d435849d0d 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -3,7 +3,7 @@ * * Module Name: evgpe - General Purpose Event handling and dispatch * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index b253063b09d3..328d1d6123ad 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -3,7 +3,7 @@ * * Module Name: evgpeblk - GPE block creation and initialization. * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 1f686750bb1a..c92d2f6ebe01 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -3,7 +3,7 @@ * * Module Name: evgpeinit - System GPE initialization and update * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 0fb6c70f44ed..917892227e09 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -3,7 +3,7 @@ * * Module Name: evgpeutil - GPE utilities * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 4ed1e67db6be..3ef4e27995f0 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -3,7 +3,7 @@ * * Module Name: evhandler - Support for Address Space handlers * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index baadd635b5af..d45f7639f7ee 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -3,7 +3,7 @@ * * Module Name: evmisc - Miscellaneous event manager support functions * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 49decca4e08f..b683b3ad6baa 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -3,7 +3,7 @@ * * Module Name: evregion - Operation Region support * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 17df5dacd43c..163dd4a142eb 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -3,7 +3,7 @@ * * Module Name: evrgnini- ACPI address_space (op_region) init * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index febc332b00ac..3df00eb6621b 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -3,7 +3,7 @@ * * Module Name: evxface - External interfaces for ACPI events * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 970e940bdb17..e528fe56b755 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -3,7 +3,7 @@ * * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index b2d5f66cc1b0..fb1d215dd288 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -3,7 +3,7 @@ * * Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 3b3a25d9f0e6..47265b073e6f 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -4,7 +4,7 @@ * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and * Address Spaces. * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exconcat.c b/drivers/acpi/acpica/exconcat.c index 5e75c510ca25..c7af07566b7b 100644 --- a/drivers/acpi/acpica/exconcat.c +++ b/drivers/acpi/acpica/exconcat.c @@ -3,7 +3,7 @@ * * Module Name: exconcat - Concatenate-type AML operators * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 2373a7492151..587aeeeb5070 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -3,7 +3,7 @@ * * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 1a70b80cc406..f5675f1b1928 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -3,7 +3,7 @@ * * Module Name: exconvrt - Object conversion routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 3304c6b1e8a7..f376fc00064e 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -3,7 +3,7 @@ * * Module Name: excreate - Named object creation * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index ebbc244039ab..b1aeec8cac55 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -3,7 +3,7 @@ * * Module Name: exdebug - Support for stores to the AML Debug Object * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index f71dfa1e90e1..6526b2deeaad 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -3,7 +3,7 @@ * * Module Name: exdump - Interpreter debug output routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index e5798f15793a..7dcdde094582 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -3,7 +3,7 @@ * * Module Name: exfield - AML execution - field_unit read/write * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 516994133128..95a0dcb4f7b9 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -3,7 +3,7 @@ * * Module Name: exfldio - Aml Field I/O * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index d91f15cdf3ae..60e854965af9 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -3,7 +3,7 @@ * * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index c06079774bad..775cd62af5b3 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -3,7 +3,7 @@ * * Module Name: exmutex - ASL Mutex Acquire/Release functions * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index 7eed79dcda83..bd68d66e89f0 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -3,7 +3,7 @@ * * Module Name: exnames - interpreter/scanner name load/execute * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index ba9fbae0cf91..06e35ea09823 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -3,7 +3,7 @@ * * Module Name: exoparg1 - AML execution - opcodes with 1 argument * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index e9509b1c9a3a..5e4a31a11df4 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -3,7 +3,7 @@ * * Module Name: exoparg2 - AML execution - opcodes with 2 arguments * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 764fa6f924ff..a4ebce417930 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -3,7 +3,7 @@ * * Module Name: exoparg3 - AML execution - opcodes with 3 arguments * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 3941525f3d6b..31385a0b2dab 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -3,7 +3,7 @@ * * Module Name: exoparg6 - AML execution - opcodes with 6 arguments * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 738f3c732363..728d752f7adc 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -3,7 +3,7 @@ * * Module Name: exprep - ACPI AML field prep utilities * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 2c58f5e00b1a..c08521194b29 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -3,7 +3,7 @@ * * Module Name: exregion - ACPI default op_region (address space) handlers * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index ea4b0fe674f1..b223d01e6bf8 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -3,7 +3,7 @@ * * Module Name: exresnte - AML Interpreter object resolution * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index 5e42c7de46fa..36da5c0ef69c 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -3,7 +3,7 @@ * * Module Name: exresolv - AML Interpreter object resolution * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index d94190bc5985..bdfe4d33b483 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -3,7 +3,7 @@ * * Module Name: exresop - AML Interpreter operand/object resolution * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exserial.c b/drivers/acpi/acpica/exserial.c index ec61553c4483..89bc0a2d8163 100644 --- a/drivers/acpi/acpica/exserial.c +++ b/drivers/acpi/acpica/exserial.c @@ -3,7 +3,7 @@ * * Module Name: exserial - field_unit support for serial address spaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 75d5665b7b2f..7f3c3571c292 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -3,7 +3,7 @@ * * Module Name: exstore - AML Interpreter object store support * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index 31cba19652ed..4e43c8277f07 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -4,7 +4,7 @@ * Module Name: exstoren - AML Interpreter object store support, * Store to Node (namespace object) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index 4cd82ff509bc..dc9e2b1c1ad9 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -3,7 +3,7 @@ * * Module Name: exstorob - AML object store support, store to object * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index ec8b5a22cad4..a538f7799b78 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -3,7 +3,7 @@ * * Module Name: exsystem - Interface to OS services * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/extrace.c b/drivers/acpi/acpica/extrace.c index 9bd3fa56b51a..db7f93ca539f 100644 --- a/drivers/acpi/acpica/extrace.c +++ b/drivers/acpi/acpica/extrace.c @@ -3,7 +3,7 @@ * * Module Name: extrace - Support for interpreter execution tracing * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index bd22e27adf9b..a1f26b0ad449 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -3,7 +3,7 @@ * * Module Name: exutils - interpreter/scanner utilities * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index 525e6ea5c114..926f7e080f22 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -3,7 +3,7 @@ * * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index e0ad3f11142e..dee3affaca49 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -4,7 +4,7 @@ * Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the * extended FADT-V5 sleep registers. * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 2d2e2e41a685..565bd3f29f31 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -3,7 +3,7 @@ * * Module Name: hwgpe - Low level GPE enable/disable/clear functions * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index d8b8fc2ff563..b62db8ec446f 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -4,7 +4,7 @@ * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the * original/legacy sleep/PM registers. * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 5d5e27146fc2..2fb9f75d71c5 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -3,7 +3,7 @@ * * Name: hwtimer.c - ACPI Power Management Timer Interface * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 24f9b61aa404..cd576153257c 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -3,7 +3,7 @@ * * Module Name: hwvalid - I/O request validation * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 6e39a771a56e..c4fd97104024 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -3,7 +3,7 @@ * * Module Name: hwxface - Public ACPICA hardware interfaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 3f22f7dd4556..669fa73dd794 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -3,7 +3,7 @@ * * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c index b9ede797b654..0e97ed38973f 100644 --- a/drivers/acpi/acpica/nsarguments.c +++ b/drivers/acpi/acpica/nsarguments.c @@ -3,7 +3,7 @@ * * Module Name: nsarguments - Validation of args for ACPI predefined methods * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index f9527346b0f7..14cbf63f1991 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -4,7 +4,7 @@ * Module Name: nsconvert - Object conversions for objects returned by * predefined methods * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 90ccffcd770b..15070bd0c28a 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -3,7 +3,7 @@ * * Module Name: nsdump - table dumping routines for debug * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 2b291c500fb0..73e5c83c8c9f 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -3,7 +3,7 @@ * * Module Name: nsdump - table dumping routines for debug * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index d77257d1c827..19fb8dda870f 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -3,7 +3,7 @@ * * Module Name: nsinit - namespace initialization * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 04bc73e82aed..6b90aa89f942 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -3,7 +3,7 @@ * * Module Name: nsload - namespace loading/expanding/contracting procedures * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 488ff39d86f7..bfa408f7fd39 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -3,7 +3,7 @@ * * Module Name: nsparse - namespace interface to AML parser * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 29c68b15a64f..2f9d93122d0c 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -3,7 +3,7 @@ * * Module Name: nspredef - Validation of ACPI predefined methods and objects * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c index 51523473e7fe..9a80e3b23496 100644 --- a/drivers/acpi/acpica/nsprepkg.c +++ b/drivers/acpi/acpica/nsprepkg.c @@ -3,7 +3,7 @@ * * Module Name: nsprepkg - Validation of package objects for predefined names * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index ff2ab8fbec38..0aacfa48e20d 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -3,7 +3,7 @@ * * Module Name: nsrepair - Repair for objects returned by predefined methods * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index a3bd6280882c..d5804a6d1d65 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -4,7 +4,7 @@ * Module Name: nsrepair2 - Repair for objects returned by specific * predefined methods * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index a2bf4b2caa6c..0c5662c4168c 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -4,7 +4,7 @@ * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing * parents and siblings and Scope manipulation * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index e9a061da9bb2..ceea6af79d12 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -3,7 +3,7 @@ * * Module Name: nswalk - Functions for walking the ACPI namespace * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index b2915c9cceaf..de2d3135d6a9 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -4,7 +4,7 @@ * Module Name: nsxfname - Public interfaces to the ACPI subsystem * ACPI Namespace oriented interfaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 176d28d60125..9d9d442cd999 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -3,7 +3,7 @@ * * Module Name: psargs - Parse AML opcode arguments * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index e00d1af6fa80..4796f17805ac 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -3,7 +3,7 @@ * * Module Name: psloop - Main AML parse loop * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index e1fd819a2955..98e5c7400e54 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -3,7 +3,7 @@ * * Module Name: psobject - Support for parse objects * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index 8d7dc98bad17..43775c5ce17c 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -3,7 +3,7 @@ * * Module Name: psopcode - Parser/Interpreter opcode information table * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index f310954eea59..15e7563829f1 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -3,7 +3,7 @@ * * Module Name: psopinfo - AML opcode information functions and dispatch tables * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 65603473b6cb..3f381ffd9581 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -3,7 +3,7 @@ * * Module Name: psparse - Parser top level AML parse routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c index 00c67bc249aa..f153ca804740 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -3,7 +3,7 @@ * * Module Name: psscope - Parser scope stack management routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index 64a8329a17f1..22d8a2becdd0 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -3,7 +3,7 @@ * * Module Name: pstree - Parser op tree manipulation/traversal/search * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index ef8a5805a836..2512f584fa3c 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -3,7 +3,7 @@ * * Module Name: psutils - Parser miscellaneous utilities (Parser only) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index bd6af8c87d48..cf91841297c2 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -3,7 +3,7 @@ * * Module Name: pswalk - Parser routines to walk parsed op tree(s) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 5743b22399a0..ee2ee2c858f2 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -3,7 +3,7 @@ * * Module Name: psxface - Parser external interfaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 862149c8a208..0cecd0039acf 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -3,7 +3,7 @@ * * Module Name: tbdata - Table manager data structure functions * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 99d325a51816..2c67351d5a79 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -3,7 +3,7 @@ * * Module Name: tbfadt - FADT table utilities * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index f00694b1d000..951bd8e1c50a 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -3,7 +3,7 @@ * * Module Name: tbfind - find table * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 5f8e7b561c90..be6642bf6366 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -3,7 +3,7 @@ * * Module Name: tbinstal - ACPI table installation and removal * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index e303418a895b..9b5df95d881b 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -3,7 +3,7 @@ * * Module Name: tbprint - Table output utilities * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index b526096560b5..2469e01310e2 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -3,7 +3,7 @@ * * Module Name: tbutils - ACPI Table utilities * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index e4d0dc8948cd..593c20c20104 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -3,7 +3,7 @@ * * Module Name: tbxface - ACPI table-oriented external interfaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 9011297552af..2c573fcc8c70 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -3,7 +3,7 @@ * * Module Name: tbxfload - Table load/unload external interfaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 483d0ce5180a..e2859d09ca2e 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -3,7 +3,7 @@ * * Module Name: tbxfroot - Find the root ACPI table (RSDT) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c index dbabe680ff58..bb260376bd59 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -3,7 +3,7 @@ * * Module Name: utaddress - op_region address range check * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 8cbcd7d6bd5e..d64da4d9e8d0 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -3,7 +3,7 @@ * * Module Name: utalloc - local memory allocation routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utascii.c b/drivers/acpi/acpica/utascii.c index 04ff61e284f5..79d7426fd7bf 100644 --- a/drivers/acpi/acpica/utascii.c +++ b/drivers/acpi/acpica/utascii.c @@ -3,7 +3,7 @@ * * Module Name: utascii - Utility ascii functions * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index fffa6f5ae59e..61db9967ebe4 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -3,7 +3,7 @@ * * Module Name: utbuffer - Buffer dump routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index 97d6ec174c28..8533fce7fa93 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -3,7 +3,7 @@ * * Module Name: utcache - local cache allocation routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index a872ed7879ca..1fb8327f3c3b 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -3,7 +3,7 @@ * * Module Name: utcopy - Internal to external object translation utilities * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index aabdc25effd9..01b1b36c8a8e 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -3,7 +3,7 @@ * * Module Name: utdebug - Debug print/trace routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index d0a375c3f4e2..6be69c28c34e 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -3,7 +3,7 @@ * * Module Name: utdecode - Utility decoding routines (value-to-string) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index c56ae6e058d5..558a9f3b0678 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -3,7 +3,7 @@ * * Module Name: uteval - Object evaluation * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index f8c5b49344df..b0622ec4bb85 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -3,7 +3,7 @@ * * Module Name: utglobal - Global variables for the ACPI subsystem * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c index 3d63a9e8da4f..b6da135d5f41 100644 --- a/drivers/acpi/acpica/uthex.c +++ b/drivers/acpi/acpica/uthex.c @@ -3,7 +3,7 @@ * * Module Name: uthex -- Hex/ASCII support functions * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 70e6bf1107a1..e805abdd95b8 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -3,7 +3,7 @@ * * Module Name: utids - support for device Ids - HID, UID, CID, SUB, CLS * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 0646ed62b351..bc124591320e 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -3,7 +3,7 @@ * * Module Name: utinit - Common ACPI subsystem initialization * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index d61e01bd01a3..8b4ff11d617a 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -3,7 +3,7 @@ * * Module Name: utlock - Reader/Writer lock interfaces * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index ae6d8cc18cec..eee97a902696 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -3,7 +3,7 @@ * * Module Name: utobject - ACPI object create/delete/size/cache routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 902a47463abf..688c61a90725 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -3,7 +3,7 @@ * * Module Name: utosi - Support for the _OSI predefined control method * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c index 65ca9807c2a8..a9f08f43c685 100644 --- a/drivers/acpi/acpica/utpredef.c +++ b/drivers/acpi/acpica/utpredef.c @@ -3,7 +3,7 @@ * * Module Name: utpredef - support functions for predefined names * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index a98c334c3bb7..5839f2fa7400 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -3,7 +3,7 @@ * * Module Name: utprint - Formatted printing routines * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index f6b55e2482ee..8052f7ef5025 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -3,7 +3,7 @@ * * Module Name: uttrack - Memory allocation tracking routines (debug only) * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utuuid.c b/drivers/acpi/acpica/utuuid.c index 59ae118092a3..0a7cf8007643 100644 --- a/drivers/acpi/acpica/utuuid.c +++ b/drivers/acpi/acpica/utuuid.c @@ -3,7 +3,7 @@ * * Module Name: utuuid -- UUID support functions * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index d2d6cc065181..f497c4b30e65 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -3,7 +3,7 @@ * * Module Name: utxface - External interfaces, miscellaneous utility functions * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index e3c60f57c9f0..9f3b1e3a09de 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -3,7 +3,7 @@ * * Module Name: utxfinit - External interfaces for ACPICA initialization * - * Copyright (C) 2000 - 2018, Intel Corp. + * Copyright (C) 2000 - 2019, Intel Corp. * *****************************************************************************/ -- cgit v1.2.3 From 1f9c7840e81ad81dd99cf5ad74843316b935402f Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Dec 2018 10:03:21 -0800 Subject: ice: Refactor a few Tx scheduler functions The following functions were refactored to call a new common function, ice_aqc_send_sched_elem_cmd(): - ice_aq_add_sched_elems() - ice_aq_delete_sched_elems() - ice_aq_move_sched_elems() - ice_aq_query_sched_elems() - ice_aq_cfg_sched_elems() - ice_aq_suspend_sched_elems() - ice_aq_resume_sched_elems() Signed-off-by: Greg Priest Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 22 ++--- drivers/net/ethernet/intel/ice/ice_sched.c | 122 +++++++++--------------- 2 files changed, 53 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index fcdcd80b18e7..4c7e3af07254 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -657,8 +657,13 @@ struct ice_aqc_get_topo { /* Update TSE (indirect 0x0403) * Get TSE (indirect 0x0404) + * Add TSE (indirect 0x0401) + * Delete TSE (indirect 0x040F) + * Move TSE (indirect 0x0408) + * Suspend Nodes (indirect 0x0409) + * Resume Nodes (indirect 0x040A) */ -struct ice_aqc_get_cfg_elem { +struct ice_aqc_sched_elem_cmd { __le16 num_elem_req; /* Used by commands */ __le16 num_elem_resp; /* Used by responses */ __le32 reserved; @@ -674,18 +679,6 @@ struct ice_aqc_suspend_resume_elem { __le32 teid[1]; }; -/* Add TSE (indirect 0x0401) - * Delete TSE (indirect 0x040F) - * Move TSE (indirect 0x0408) - */ -struct ice_aqc_add_move_delete_elem { - __le16 num_grps_req; - __le16 num_grps_updated; - __le32 reserved; - __le32 addr_high; - __le32 addr_low; -}; - struct ice_aqc_elem_info_bw { __le16 bw_profile_idx; __le16 bw_alloc; @@ -1344,9 +1337,8 @@ struct ice_aq_desc { struct ice_aqc_get_sw_cfg get_sw_conf; struct ice_aqc_sw_rules sw_rules; struct ice_aqc_get_topo get_topo; - struct ice_aqc_get_cfg_elem get_update_elem; + struct ice_aqc_sched_elem_cmd sched_elem_cmd; struct ice_aqc_query_txsched_res query_sched_res; - struct ice_aqc_add_move_delete_elem add_move_delete_elem; struct ice_aqc_nvm nvm; struct ice_aqc_pf_vf_msg virt; struct ice_aqc_get_set_rss_lut get_set_rss_lut; diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index a1681853df2e..99d51990bd54 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -85,36 +85,58 @@ ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid) } /** - * ice_aq_query_sched_elems - query scheduler elements + * ice_aqc_send_sched_elem_cmd - send scheduling elements cmd * @hw: pointer to the hw struct - * @elems_req: number of elements to query + * @cmd_opc: cmd opcode + * @elems_req: number of elements to request * @buf: pointer to buffer * @buf_size: buffer size in bytes - * @elems_ret: returns total number of elements returned + * @elems_resp: returns total number of elements response * @cd: pointer to command details structure or NULL * - * Query scheduling elements (0x0404) + * This function sends a scheduling elements cmd (cmd_opc) */ static enum ice_status -ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req, - struct ice_aqc_get_elem *buf, u16 buf_size, - u16 *elems_ret, struct ice_sq_cd *cd) +ice_aqc_send_sched_elem_cmd(struct ice_hw *hw, enum ice_adminq_opc cmd_opc, + u16 elems_req, void *buf, u16 buf_size, + u16 *elems_resp, struct ice_sq_cd *cd) { - struct ice_aqc_get_cfg_elem *cmd; + struct ice_aqc_sched_elem_cmd *cmd; struct ice_aq_desc desc; enum ice_status status; - cmd = &desc.params.get_update_elem; - ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sched_elems); + cmd = &desc.params.sched_elem_cmd; + ice_fill_dflt_direct_cmd_desc(&desc, cmd_opc); cmd->num_elem_req = cpu_to_le16(elems_req); desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); - if (!status && elems_ret) - *elems_ret = le16_to_cpu(cmd->num_elem_resp); + if (!status && elems_resp) + *elems_resp = le16_to_cpu(cmd->num_elem_resp); return status; } +/** + * ice_aq_query_sched_elems - query scheduler elements + * @hw: pointer to the hw struct + * @elems_req: number of elements to query + * @buf: pointer to buffer + * @buf_size: buffer size in bytes + * @elems_ret: returns total number of elements returned + * @cd: pointer to command details structure or NULL + * + * Query scheduling elements (0x0404) + */ +static enum ice_status +ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req, + struct ice_aqc_get_elem *buf, u16 buf_size, + u16 *elems_ret, struct ice_sq_cd *cd) +{ + return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_get_sched_elems, + elems_req, (void *)buf, buf_size, + elems_ret, cd); +} + /** * ice_sched_query_elem - query element information from hw * @hw: pointer to the hw struct @@ -218,20 +240,9 @@ ice_aq_delete_sched_elems(struct ice_hw *hw, u16 grps_req, struct ice_aqc_delete_elem *buf, u16 buf_size, u16 *grps_del, struct ice_sq_cd *cd) { - struct ice_aqc_add_move_delete_elem *cmd; - struct ice_aq_desc desc; - enum ice_status status; - - cmd = &desc.params.add_move_delete_elem; - ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_delete_sched_elems); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); - cmd->num_grps_req = cpu_to_le16(grps_req); - - status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); - if (!status && grps_del) - *grps_del = le16_to_cpu(cmd->num_grps_updated); - - return status; + return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_delete_sched_elems, + grps_req, (void *)buf, buf_size, + grps_del, cd); } /** @@ -442,52 +453,9 @@ ice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req, struct ice_aqc_add_elem *buf, u16 buf_size, u16 *grps_added, struct ice_sq_cd *cd) { - struct ice_aqc_add_move_delete_elem *cmd; - struct ice_aq_desc desc; - enum ice_status status; - - cmd = &desc.params.add_move_delete_elem; - ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_sched_elems); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); - - cmd->num_grps_req = cpu_to_le16(grps_req); - status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); - if (!status && grps_added) - *grps_added = le16_to_cpu(cmd->num_grps_updated); - - return status; -} - -/** - * ice_suspend_resume_elems - suspend/resume scheduler elements - * @hw: pointer to the hw struct - * @elems_req: number of elements to suspend - * @buf: pointer to buffer - * @buf_size: buffer size in bytes - * @elems_ret: returns total number of elements suspended - * @cd: pointer to command details structure or NULL - * @cmd_code: command code for suspend or resume - * - * suspend/resume scheduler elements - */ -static enum ice_status -ice_suspend_resume_elems(struct ice_hw *hw, u16 elems_req, - struct ice_aqc_suspend_resume_elem *buf, u16 buf_size, - u16 *elems_ret, struct ice_sq_cd *cd, - enum ice_adminq_opc cmd_code) -{ - struct ice_aqc_get_cfg_elem *cmd; - struct ice_aq_desc desc; - enum ice_status status; - - cmd = &desc.params.get_update_elem; - ice_fill_dflt_direct_cmd_desc(&desc, cmd_code); - cmd->num_elem_req = cpu_to_le16(elems_req); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); - status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); - if (!status && elems_ret) - *elems_ret = le16_to_cpu(cmd->num_elem_resp); - return status; + return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_add_sched_elems, + grps_req, (void *)buf, buf_size, + grps_added, cd); } /** @@ -506,8 +474,9 @@ ice_aq_suspend_sched_elems(struct ice_hw *hw, u16 elems_req, struct ice_aqc_suspend_resume_elem *buf, u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd) { - return ice_suspend_resume_elems(hw, elems_req, buf, buf_size, elems_ret, - cd, ice_aqc_opc_suspend_sched_elems); + return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_suspend_sched_elems, + elems_req, (void *)buf, buf_size, + elems_ret, cd); } /** @@ -526,8 +495,9 @@ ice_aq_resume_sched_elems(struct ice_hw *hw, u16 elems_req, struct ice_aqc_suspend_resume_elem *buf, u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd) { - return ice_suspend_resume_elems(hw, elems_req, buf, buf_size, elems_ret, - cd, ice_aqc_opc_resume_sched_elems); + return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_resume_sched_elems, + elems_req, (void *)buf, buf_size, + elems_ret, cd); } /** -- cgit v1.2.3 From 27a98affa66000d7f96527a4a267f0d13aaecf7b Mon Sep 17 00:00:00 2001 From: Md Fahad Iqbal Polash Date: Wed, 19 Dec 2018 10:03:22 -0800 Subject: ice: Configure RSS LUT and HASH KEY in rebuild path This patch configures the RSS lookup table and hash key post reset. Signed-off-by: Md Fahad Iqbal Polash Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 29b1dcfd4331..3bd24173b39c 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2581,6 +2581,12 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) goto err_vectors; ice_vsi_map_rings_to_vectors(vsi); + /* Do not exit if configuring RSS had an issue, at least + * receive traffic on first queue. Hence no need to capture + * return value + */ + if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) + ice_vsi_cfg_rss_lut_key(vsi); break; case ICE_VSI_VF: ret = ice_vsi_alloc_q_vectors(vsi); -- cgit v1.2.3 From 8e151d50a1450350009822b4f705c6caf83383d4 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Dec 2018 10:03:23 -0800 Subject: ice: Add ethtool set_phys_id handler Add led blinking handler to ethtool. Since led blinking is controlled by FW/HW only ETHTOOL_ID_ACTIVE and ETHTOOL_ID_INACTIVE are really needed. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 12 +++++++++++ drivers/net/ethernet/intel/ice/ice_common.c | 28 +++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_common.h | 4 ++++ drivers/net/ethernet/intel/ice/ice_ethtool.c | 24 +++++++++++++++++++++ 4 files changed, 68 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 4c7e3af07254..245068b21982 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1048,6 +1048,16 @@ struct ice_aqc_set_event_mask { u8 reserved1[6]; }; +/* Set Port Identification LED (direct, 0x06E9) */ +struct ice_aqc_set_port_id_led { + u8 lport_num; + u8 lport_num_valid; + u8 ident_mode; +#define ICE_AQC_PORT_IDENT_LED_BLINK BIT(0) +#define ICE_AQC_PORT_IDENT_LED_ORIG 0 + u8 rsvd[13]; +}; + /* NVM Read command (indirect 0x0701) * NVM Erase commands (direct 0x0702) * NVM Update commands (indirect 0x0703) @@ -1334,6 +1344,7 @@ struct ice_aq_desc { struct ice_aqc_get_phy_caps get_phy; struct ice_aqc_set_phy_cfg set_phy; struct ice_aqc_restart_an restart_an; + struct ice_aqc_set_port_id_led set_port_id_led; struct ice_aqc_get_sw_cfg get_sw_conf; struct ice_aqc_sw_rules sw_rules; struct ice_aqc_get_topo get_topo; @@ -1434,6 +1445,7 @@ enum ice_adminq_opc { ice_aqc_opc_restart_an = 0x0605, ice_aqc_opc_get_link_status = 0x0607, ice_aqc_opc_set_event_mask = 0x0613, + ice_aqc_opc_set_port_id_led = 0x06E9, /* NVM commands */ ice_aqc_opc_nvm_read = 0x0701, diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 4c1d35da940d..2bcd8230d35e 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2031,6 +2031,34 @@ ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link, return ice_aq_send_cmd(pi->hw, &desc, NULL, 0, cd); } +/** + * ice_aq_set_port_id_led + * @pi: pointer to the port information + * @is_orig_mode: is this LED set to original mode (by the net-list) + * @cd: pointer to command details structure or NULL + * + * Set LED value for the given port (0x06e9) + */ +enum ice_status +ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode, + struct ice_sq_cd *cd) +{ + struct ice_aqc_set_port_id_led *cmd; + struct ice_hw *hw = pi->hw; + struct ice_aq_desc desc; + + cmd = &desc.params.set_port_id_led; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_id_led); + + if (is_orig_mode) + cmd->ident_mode = ICE_AQC_PORT_IDENT_LED_ORIG; + else + cmd->ident_mode = ICE_AQC_PORT_IDENT_LED_BLINK; + + return ice_aq_send_cmd(hw, &desc, NULL, 0, cd); +} + /** * __ice_aq_get_set_rss_lut * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index cf760c24a6aa..b86cfe540045 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -86,6 +86,10 @@ enum ice_status ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link, struct ice_sq_cd *cd); enum ice_status +ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode, + struct ice_sq_cd *cd); + +enum ice_status ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, u32 *q_teids, enum ice_disq_rst_src rst_src, u16 vmvf_num, struct ice_sq_cd *cmd_details); diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 3b6e387f5440..6facb0a7eed4 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -249,6 +249,29 @@ static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data) } } +static int +ice_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + bool led_active; + + switch (state) { + case ETHTOOL_ID_ACTIVE: + led_active = true; + break; + case ETHTOOL_ID_INACTIVE: + led_active = false; + break; + default: + return -EINVAL; + } + + if (ice_aq_set_port_id_led(np->vsi->port_info, !led_active, NULL)) + return -EIO; + + return 0; +} + static int ice_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { @@ -1677,6 +1700,7 @@ static const struct ethtool_ops ice_ethtool_ops = { .set_msglevel = ice_set_msglevel, .get_link = ethtool_op_get_link, .get_strings = ice_get_strings, + .set_phys_id = ice_set_phys_id, .get_ethtool_stats = ice_get_ethtool_stats, .get_sset_count = ice_get_sset_count, .get_rxnfc = ice_get_rxnfc, -- cgit v1.2.3 From 4c98ab550cc624eb94b0cdb32f5deb1ebbb4f593 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Dec 2018 10:03:24 -0800 Subject: ice: Implement support for normal get_eeprom[_len] ethtool ops Add support for get_eeprom and get_eeprom_len ethtool ops Specification states that PF software accesses NVM (shadow-ram) via AQ commands (e.g. NVM Read, NVM Write) in the range 0x000000-0x00FFFF (64KB), so the get_eeprom_len op should return 64KB. If additional regions of the 16MB NVM must be read, another access method must be used. The ethtool kernel code, by default, will ask for multiple page-size hunks of the NVM not to exceed the value returned by ice_get_eeprom_len(). ice_read_sr_buf() deals with arch page sizes different than 4KB. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.h | 2 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 51 ++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_nvm.c | 81 ++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index b86cfe540045..81c1bb77a9fc 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -28,6 +28,8 @@ ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res, enum ice_aq_res_access_type access, u32 timeout); void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res); enum ice_status ice_init_nvm(struct ice_hw *hw); +enum ice_status ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, + u16 *data); enum ice_status ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, struct ice_aq_desc *desc, void *buf, u16 buf_size, diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 6facb0a7eed4..2a0bcd460d23 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -203,6 +203,55 @@ static void ice_set_msglevel(struct net_device *netdev, u32 data) #endif /* !CONFIG_DYNAMIC_DEBUG */ } +static int ice_get_eeprom_len(struct net_device *netdev) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = np->vsi->back; + + return (int)(pf->hw.nvm.sr_words * sizeof(u16)); +} + +static int +ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, + u8 *bytes) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + u16 first_word, last_word, nwords; + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + enum ice_status status; + struct device *dev; + int ret = 0; + u16 *buf; + + dev = &pf->pdev->dev; + + eeprom->magic = hw->vendor_id | (hw->device_id << 16); + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + nwords = last_word - first_word + 1; + + buf = devm_kcalloc(dev, nwords, sizeof(u16), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + status = ice_read_sr_buf(hw, first_word, &nwords, buf); + if (status) { + dev_err(dev, "ice_read_sr_buf failed, err %d aq_err %d\n", + status, hw->adminq.sq_last_status); + eeprom->len = sizeof(u16) * nwords; + ret = -EIO; + goto out; + } + + memcpy(bytes, (u8 *)buf + (eeprom->offset & 1), eeprom->len); +out: + devm_kfree(dev, buf); + return ret; +} + static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { struct ice_netdev_priv *np = netdev_priv(netdev); @@ -1699,6 +1748,8 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_msglevel = ice_get_msglevel, .set_msglevel = ice_set_msglevel, .get_link = ethtool_op_get_link, + .get_eeprom_len = ice_get_eeprom_len, + .get_eeprom = ice_get_eeprom, .get_strings = ice_get_strings, .set_phys_id = ice_set_phys_id, .get_ethtool_stats = ice_get_ethtool_stats, diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c index 3274c543283c..ce64cecdae9c 100644 --- a/drivers/net/ethernet/intel/ice/ice_nvm.c +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c @@ -124,6 +124,62 @@ ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data) return status; } +/** + * ice_read_sr_buf_aq - Reads Shadow RAM buf via AQ + * @hw: pointer to the HW structure + * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) + * @words: (in) number of words to read; (out) number of words actually read + * @data: words read from the Shadow RAM + * + * Reads 16 bit words (data buf) from the SR using the ice_read_sr_aq + * method. Ownership of the NVM is taken before reading the buffer and later + * released. + */ +static enum ice_status +ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data) +{ + enum ice_status status; + bool last_cmd = false; + u16 words_read = 0; + u16 i = 0; + + do { + u16 read_size, off_w; + + /* Calculate number of bytes we should read in this step. + * It's not allowed to read more than one page at a time or + * to cross page boundaries. + */ + off_w = offset % ICE_SR_SECTOR_SIZE_IN_WORDS; + read_size = off_w ? + min(*words, + (u16)(ICE_SR_SECTOR_SIZE_IN_WORDS - off_w)) : + min((*words - words_read), ICE_SR_SECTOR_SIZE_IN_WORDS); + + /* Check if this is last command, if so set proper flag */ + if ((words_read + read_size) >= *words) + last_cmd = true; + + status = ice_read_sr_aq(hw, offset, read_size, + data + words_read, last_cmd); + if (status) + goto read_nvm_buf_aq_exit; + + /* Increment counter for words already read and move offset to + * new read location + */ + words_read += read_size; + offset += read_size; + } while (words_read < *words); + + for (i = 0; i < *words; i++) + data[i] = le16_to_cpu(((__le16 *)data)[i]); + +read_nvm_buf_aq_exit: + *words = words_read; + return status; +} + /** * ice_acquire_nvm - Generic request for acquiring the NVM ownership * @hw: pointer to the HW structure @@ -234,3 +290,28 @@ enum ice_status ice_init_nvm(struct ice_hw *hw) return status; } + +/** + * ice_read_sr_buf - Reads Shadow RAM buf and acquire lock if necessary + * @hw: pointer to the HW structure + * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) + * @words: (in) number of words to read; (out) number of words actually read + * @data: words read from the Shadow RAM + * + * Reads 16 bit words (data buf) from the SR using the ice_read_nvm_buf_aq + * method. The buf read is preceded by the NVM ownership take + * and followed by the release. + */ +enum ice_status +ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data) +{ + enum ice_status status; + + status = ice_acquire_nvm(hw, ICE_RES_READ); + if (!status) { + status = ice_read_sr_buf_aq(hw, offset, words, data); + ice_release_nvm(hw); + } + + return status; +} -- cgit v1.2.3 From b6f934f027bbdb53b7e2653b23758e222f3dd65a Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Dec 2018 10:03:25 -0800 Subject: ice: Set physical link up/down when an interface is set up/down When a netdev is set up/down we need to set the phsyical link state accordingly. This patch adds that functionality by calling ice_force_phys_link_state(vsi, link_up) in both the ice_stop() and ice_open() paths. In order to force link, ice_force_phys_link_state(vsi, link_up) will first determine the current phy capabilities. If link has not changed there is nothing to do. If link has changed, previous PHY capabilities are saved and the "Enable Automatic Link Update" and "Link Establishment State Machine (LESM)" enable bits are set. Then the new PHY config is saved. The "Enable Automatic Link Update" will force the FW to execute Setup link and restart auto-negotiation. This *should* then result in a "Link Status Event (LSE)" which will cause the driver to get the current link status. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 4 +- drivers/net/ethernet/intel/ice/ice_main.c | 97 ++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 245068b21982..526224ede3fa 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -851,7 +851,7 @@ struct ice_aqc_get_phy_caps { struct ice_aqc_get_phy_caps_data { __le64 phy_type_low; /* Use values from ICE_PHY_TYPE_LOW_* */ - __le64 reserved; + __le64 phy_type_high; /* Use values from ICE_PHY_TYPE_HIGH_* */ u8 caps; #define ICE_AQC_PHY_EN_TX_LINK_PAUSE BIT(0) #define ICE_AQC_PHY_EN_RX_LINK_PAUSE BIT(1) @@ -916,7 +916,7 @@ struct ice_aqc_set_phy_cfg { /* Set PHY config command data structure */ struct ice_aqc_set_phy_cfg_data { __le64 phy_type_low; /* Use values from ICE_PHY_TYPE_LOW_* */ - __le64 rsvd0; + __le64 phy_type_high; /* Use values from ICE_PHY_TYPE_HIGH_* */ u8 caps; #define ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY BIT(0) #define ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY BIT(1) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 90773b477d19..b27bc7d6d605 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2944,13 +2944,92 @@ static void ice_napi_disable_all(struct ice_vsi *vsi) } } +/** + * ice_force_phys_link_state - Force the physical link state + * @vsi: VSI to force the physical link state to up/down + * @link_up: true/false indicates to set the physical link to up/down + * + * Force the physical link state by getting the current PHY capabilities from + * hardware and setting the PHY config based on the determined capabilities. If + * link changes a link event will be triggered because both the Enable Automatic + * Link Update and LESM Enable bits are set when setting the PHY capabilities. + * + * Returns 0 on success, negative on failure + */ +static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up) +{ + struct ice_aqc_get_phy_caps_data *pcaps; + struct ice_aqc_set_phy_cfg_data *cfg; + struct ice_port_info *pi; + struct device *dev; + int retcode; + + if (!vsi || !vsi->port_info || !vsi->back) + return -EINVAL; + if (vsi->type != ICE_VSI_PF) + return 0; + + dev = &vsi->back->pdev->dev; + + pi = vsi->port_info; + + pcaps = devm_kzalloc(dev, sizeof(*pcaps), GFP_KERNEL); + if (!pcaps) + return -ENOMEM; + + retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG, pcaps, + NULL); + if (retcode) { + dev_err(dev, + "Failed to get phy capabilities, VSI %d error %d\n", + vsi->vsi_num, retcode); + retcode = -EIO; + goto out; + } + + /* No change in link */ + if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) && + link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP)) + goto out; + + cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL); + if (!cfg) { + retcode = -ENOMEM; + goto out; + } + + cfg->phy_type_low = pcaps->phy_type_low; + cfg->phy_type_high = pcaps->phy_type_high; + cfg->caps = pcaps->caps | ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; + cfg->low_power_ctrl = pcaps->low_power_ctrl; + cfg->eee_cap = pcaps->eee_cap; + cfg->eeer_value = pcaps->eeer_value; + cfg->link_fec_opt = pcaps->link_fec_options; + if (link_up) + cfg->caps |= ICE_AQ_PHY_ENA_LINK; + else + cfg->caps &= ~ICE_AQ_PHY_ENA_LINK; + + retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi->lport, cfg, NULL); + if (retcode) { + dev_err(dev, "Failed to set phy config, VSI %d error %d\n", + vsi->vsi_num, retcode); + retcode = -EIO; + } + + devm_kfree(dev, cfg); +out: + devm_kfree(dev, pcaps); + return retcode; +} + /** * ice_down - Shutdown the connection * @vsi: The VSI being stopped */ int ice_down(struct ice_vsi *vsi) { - int i, tx_err, rx_err; + int i, tx_err, rx_err, link_err; /* Caller of this function is expected to set the * vsi->state __ICE_DOWN bit @@ -2975,13 +3054,19 @@ int ice_down(struct ice_vsi *vsi) ice_napi_disable_all(vsi); + link_err = ice_force_phys_link_state(vsi, false); + if (link_err) + netdev_err(vsi->netdev, + "Failed to set physical link down, VSI %d error %d\n", + vsi->vsi_num, link_err); + ice_for_each_txq(vsi, i) ice_clean_tx_ring(vsi->tx_rings[i]); ice_for_each_rxq(vsi, i) ice_clean_rx_ring(vsi->rx_rings[i]); - if (tx_err || rx_err) { + if (tx_err || rx_err || link_err) { netdev_err(vsi->netdev, "Failed to close VSI 0x%04X on switch 0x%04X\n", vsi->vsi_num, vsi->vsw->sw_id); @@ -3815,8 +3900,14 @@ static int ice_open(struct net_device *netdev) netif_carrier_off(netdev); - err = ice_vsi_open(vsi); + err = ice_force_phys_link_state(vsi, true); + if (err) { + netdev_err(netdev, + "Failed to set physical link up, error %d\n", err); + return err; + } + err = ice_vsi_open(vsi); if (err) netdev_err(netdev, "Failed to open VSI 0x%04X on switch 0x%04X\n", vsi->vsi_num, vsi->vsw->sw_id); -- cgit v1.2.3 From ab4ab73fc1ec6dec548fa36c5e383ef5faa7b4c1 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Dec 2018 10:03:26 -0800 Subject: ice: Add ethtool private flag to make forcing link down optional Add new infrastructure for implementing ethtool private flags using the existing pf->flags bitmap to store them, and add the link-down-on-close ethtool private flag to optionally bring down the PHY link when the interface is administratively downed. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 86 ++++++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_main.c | 14 +++-- 3 files changed, 95 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index a385575600f6..8af882a2b070 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -270,6 +270,7 @@ enum ice_pf_flags { ICE_FLAG_RSS_ENA, ICE_FLAG_SRIOV_ENA, ICE_FLAG_SRIOV_CAPABLE, + ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, ICE_PF_FLAGS_NBITS /* must be last */ }; diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 2a0bcd460d23..24c8aeaea2d5 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -114,6 +114,22 @@ static const u32 ice_regs_dump_list[] = { QRX_ITR(0), }; +struct ice_priv_flag { + char name[ETH_GSTRING_LEN]; + u32 bitno; /* bit position in pf->flags */ +}; + +#define ICE_PRIV_FLAG(_name, _bitno) { \ + .name = _name, \ + .bitno = _bitno, \ +} + +static const struct ice_priv_flag ice_gstrings_priv_flags[] = { + ICE_PRIV_FLAG("link-down-on-close", ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA), +}; + +#define ICE_PRIV_FLAG_ARRAY_SIZE ARRAY_SIZE(ice_gstrings_priv_flags) + /** * ice_nvm_version_str - format the NVM version strings * @hw: ptr to the hardware info @@ -152,6 +168,7 @@ ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, pci_name(pf->pdev), sizeof(drvinfo->bus_info)); + drvinfo->n_priv_flags = ICE_PRIV_FLAG_ARRAY_SIZE; } static int ice_get_regs_len(struct net_device __always_unused *netdev) @@ -292,6 +309,13 @@ static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data) p += ETH_GSTRING_LEN; } + break; + case ETH_SS_PRIV_FLAGS: + for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { + snprintf(p, ETH_GSTRING_LEN, "%s", + ice_gstrings_priv_flags[i].name); + p += ETH_GSTRING_LEN; + } break; default: break; @@ -321,6 +345,64 @@ ice_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) return 0; } +/** + * ice_get_priv_flags - report device private flags + * @netdev: network interface device structure + * + * The get string set count and the string set should be matched for each + * flag returned. Add new strings for each flag to the ice_gstrings_priv_flags + * array. + * + * Returns a u32 bitmap of flags. + */ +static u32 ice_get_priv_flags(struct net_device *netdev) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + u32 i, ret_flags = 0; + + for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { + const struct ice_priv_flag *priv_flag; + + priv_flag = &ice_gstrings_priv_flags[i]; + + if (test_bit(priv_flag->bitno, pf->flags)) + ret_flags |= BIT(i); + } + + return ret_flags; +} + +/** + * ice_set_priv_flags - set private flags + * @netdev: network interface device structure + * @flags: bit flags to be set + */ +static int ice_set_priv_flags(struct net_device *netdev, u32 flags) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + u32 i; + + if (flags > BIT(ICE_PRIV_FLAG_ARRAY_SIZE)) + return -EINVAL; + + for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { + const struct ice_priv_flag *priv_flag; + + priv_flag = &ice_gstrings_priv_flags[i]; + + if (flags & BIT(i)) + set_bit(priv_flag->bitno, pf->flags); + else + clear_bit(priv_flag->bitno, pf->flags); + } + + return 0; +} + static int ice_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { @@ -344,6 +426,8 @@ static int ice_get_sset_count(struct net_device *netdev, int sset) * not safe. */ return ICE_ALL_STATS_LEN(netdev); + case ETH_SS_PRIV_FLAGS: + return ICE_PRIV_FLAG_ARRAY_SIZE; default: return -EOPNOTSUPP; } @@ -1753,6 +1837,8 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_strings = ice_get_strings, .set_phys_id = ice_set_phys_id, .get_ethtool_stats = ice_get_ethtool_stats, + .get_priv_flags = ice_get_priv_flags, + .set_priv_flags = ice_set_priv_flags, .get_sset_count = ice_get_sset_count, .get_rxnfc = ice_get_rxnfc, .get_ringparam = ice_get_ringparam, diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b27bc7d6d605..e36db981f047 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3029,7 +3029,7 @@ out: */ int ice_down(struct ice_vsi *vsi) { - int i, tx_err, rx_err, link_err; + int i, tx_err, rx_err, link_err = 0; /* Caller of this function is expected to set the * vsi->state __ICE_DOWN bit @@ -3054,11 +3054,13 @@ int ice_down(struct ice_vsi *vsi) ice_napi_disable_all(vsi); - link_err = ice_force_phys_link_state(vsi, false); - if (link_err) - netdev_err(vsi->netdev, - "Failed to set physical link down, VSI %d error %d\n", - vsi->vsi_num, link_err); + if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) { + link_err = ice_force_phys_link_state(vsi, false); + if (link_err) + netdev_err(vsi->netdev, + "Failed to set physical link down, VSI %d error %d\n", + vsi->vsi_num, link_err); + } ice_for_each_txq(vsi, i) ice_clean_tx_ring(vsi->tx_rings[i]); -- cgit v1.2.3 From 966d23a006ca7b44ac8cf4d0c96b19785e0c3da0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 15 Jan 2019 10:47:00 -0800 Subject: libnvdimm/label: Clear 'updating' flag after label-set update The UEFI 2.7 specification sets expectations that the 'updating' flag is eventually cleared. To date, the libnvdimm core has never adhered to that protocol. The policy of the core matches the policy of other multi-device info-block formats like MD-Software-RAID that expect administrator intervention on inconsistent info-blocks, not automatic invalidation. However, some pre-boot environments may unfortunately attempt to "clean up" the labels and invalidate a set when it fails to find at least one "non-updating" label in the set. Clear the updating flag after set updates to minimize the window of vulnerability to aggressive pre-boot environments. Ideally implementations would not write to the label area outside of creating namespaces. Note that this only minimizes the window, it does not close it as the system can still crash while clearing the flag and the set can be subsequently deleted / invalidated by the pre-boot environment. Fixes: f524bf271a5c ("libnvdimm: write pmem label set") Cc: Cc: Kelly Couch Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index a11bf4e6b451..6d6e9a12150b 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -755,7 +755,7 @@ static const guid_t *to_abstraction_guid(enum nvdimm_claim_class claim_class, static int __pmem_label_update(struct nd_region *nd_region, struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm, - int pos) + int pos, unsigned long flags) { struct nd_namespace_common *ndns = &nspm->nsio.common; struct nd_interleave_set *nd_set = nd_region->nd_set; @@ -796,7 +796,7 @@ static int __pmem_label_update(struct nd_region *nd_region, 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(NSLABEL_FLAG_UPDATING); + 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); @@ -1249,13 +1249,13 @@ static int del_labels(struct nd_mapping *nd_mapping, u8 *uuid) int nd_pmem_namespace_label_update(struct nd_region *nd_region, struct nd_namespace_pmem *nspm, resource_size_t size) { - int i; + int i, rc; for (i = 0; i < nd_region->ndr_mappings; i++) { struct nd_mapping *nd_mapping = &nd_region->mapping[i]; struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); struct resource *res; - int rc, count = 0; + int count = 0; if (size == 0) { rc = del_labels(nd_mapping, nspm->uuid); @@ -1273,7 +1273,20 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region, if (rc < 0) return rc; - rc = __pmem_label_update(nd_region, nd_mapping, nspm, i); + rc = __pmem_label_update(nd_region, nd_mapping, nspm, i, + NSLABEL_FLAG_UPDATING); + if (rc) + return rc; + } + + if (size == 0) + return 0; + + /* Clear the UPDATING flag per UEFI 2.7 expectations */ + for (i = 0; i < nd_region->ndr_mappings; i++) { + struct nd_mapping *nd_mapping = &nd_region->mapping[i]; + + rc = __pmem_label_update(nd_region, nd_mapping, nspm, i, 0); if (rc) return rc; } -- cgit v1.2.3 From d1d6bd785da0c0c08523ee4f1a2d6a0875aa6f41 Mon Sep 17 00:00:00 2001 From: Silvio Cesare Date: Sat, 12 Jan 2019 16:28:44 +0100 Subject: spi: dw: change snprintf to scnprintf for possible overflow Change snprintf to scnprintf. There are generally two cases where using snprintf causes problems. 1) Uses of size += snprintf(buf, SIZE - size, fmt, ...) In this case, if snprintf would have written more characters than what the buffer size (SIZE) is, then size will end up larger than SIZE. In later uses of snprintf, SIZE - size will result in a negative number, leading to problems. Note that size might already be too large by using size = snprintf before the code reaches a case of size += snprintf. 2) If size is ultimately used as a length parameter for a copy back to user space, then it will potentially allow for a buffer overflow and information disclosure when size is greater than SIZE. When the size is used to index the buffer directly, we can have memory corruption. This also means when size = snprintf... is used, it may also cause problems since size may become large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel configuration. The solution to these issues is to use scnprintf which returns the number of characters actually written to the buffer, so the size variable will never exceed SIZE. Signed-off-by: Silvio Cesare Signed-off-by: Willy Tarreau Reviewed-by: Kees Cook Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 2e822a56576a..4c9deb434b3a 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -54,41 +54,41 @@ static ssize_t dw_spi_show_regs(struct file *file, char __user *user_buf, if (!buf) return 0; - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "%s registers:\n", dev_name(&dws->master->dev)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "=================================\n"); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "CTRL0: \t\t0x%08x\n", dw_readl(dws, DW_SPI_CTRL0)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "CTRL1: \t\t0x%08x\n", dw_readl(dws, DW_SPI_CTRL1)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "SSIENR: \t0x%08x\n", dw_readl(dws, DW_SPI_SSIENR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "SER: \t\t0x%08x\n", dw_readl(dws, DW_SPI_SER)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "BAUDR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_BAUDR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "TXFTLR: \t0x%08x\n", dw_readl(dws, DW_SPI_TXFLTR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "RXFTLR: \t0x%08x\n", dw_readl(dws, DW_SPI_RXFLTR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "TXFLR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_TXFLR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "RXFLR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_RXFLR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "SR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_SR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "IMR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_IMR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "ISR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_ISR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "DMACR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_DMACR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "DMATDLR: \t0x%08x\n", dw_readl(dws, DW_SPI_DMATDLR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "DMARDLR: \t0x%08x\n", dw_readl(dws, DW_SPI_DMARDLR)); - len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, + len += scnprintf(buf + len, SPI_REGS_BUFSIZE - len, "=================================\n"); ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); -- cgit v1.2.3 From 03f7a986684597607de02f3023aa6c3657a78ab5 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Dec 2018 10:03:27 -0800 Subject: ice: Rework queue management code for reuse This patch reworks the queue management code to allow for reuse with the XDP feature (to be added in a future patch). Signed-off-by: Maciej Fijalkowski Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 11 ++ drivers/net/ethernet/intel/ice/ice_lib.c | 236 ++++++++++++----------- drivers/net/ethernet/intel/ice/ice_lib.h | 5 +- drivers/net/ethernet/intel/ice/ice_main.c | 6 +- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 24 ++- 5 files changed, 159 insertions(+), 123 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 8af882a2b070..ffe4ffe16912 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -129,6 +129,17 @@ struct ice_res_tracker { u16 list[1]; }; +struct ice_qs_cfg { + struct mutex *qs_mutex; /* will be assgined to &pf->avail_q_mutex */ + unsigned long *pf_map; + unsigned long pf_map_size; + unsigned int q_count; + unsigned int scatter_count; + u16 *vsi_map; + u16 vsi_map_offset; + u8 mapping_mode; +}; + struct ice_sw { struct ice_pf *pf; u16 sw_id; /* switch ID for this switch */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 3bd24173b39c..a1f523a9d39d 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -514,109 +514,88 @@ unlock_pf: } /** - * ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI - * @vsi: the VSI getting queues + * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI + * @qs_cfg: gathered variables needed for PF->VSI queues assignment * - * Return 0 on success and a negative value on error + * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap */ -static int ice_vsi_get_qs_contig(struct ice_vsi *vsi) +static int __ice_vsi_get_qs_contig(struct ice_qs_cfg *qs_cfg) { - struct ice_pf *pf = vsi->back; - int offset, ret = 0; - - mutex_lock(&pf->avail_q_mutex); - /* look for contiguous block of queues for Tx */ - offset = bitmap_find_next_zero_area(pf->avail_txqs, ICE_MAX_TXQS, - 0, vsi->alloc_txq, 0); - if (offset < ICE_MAX_TXQS) { - int i; + int offset, i; - bitmap_set(pf->avail_txqs, offset, vsi->alloc_txq); - for (i = 0; i < vsi->alloc_txq; i++) - vsi->txq_map[i] = i + offset; - } else { - ret = -ENOMEM; - vsi->tx_mapping_mode = ICE_VSI_MAP_SCATTER; + mutex_lock(qs_cfg->qs_mutex); + offset = bitmap_find_next_zero_area(qs_cfg->pf_map, qs_cfg->pf_map_size, + 0, qs_cfg->q_count, 0); + if (offset >= qs_cfg->pf_map_size) { + mutex_unlock(qs_cfg->qs_mutex); + return -ENOMEM; } - /* look for contiguous block of queues for Rx */ - offset = bitmap_find_next_zero_area(pf->avail_rxqs, ICE_MAX_RXQS, - 0, vsi->alloc_rxq, 0); - if (offset < ICE_MAX_RXQS) { - int i; - - bitmap_set(pf->avail_rxqs, offset, vsi->alloc_rxq); - for (i = 0; i < vsi->alloc_rxq; i++) - vsi->rxq_map[i] = i + offset; - } else { - ret = -ENOMEM; - vsi->rx_mapping_mode = ICE_VSI_MAP_SCATTER; - } - mutex_unlock(&pf->avail_q_mutex); + bitmap_set(qs_cfg->pf_map, offset, qs_cfg->q_count); + for (i = 0; i < qs_cfg->q_count; i++) + qs_cfg->vsi_map[i + qs_cfg->vsi_map_offset] = i + offset; + mutex_unlock(qs_cfg->qs_mutex); - return ret; + return 0; } /** - * ice_vsi_get_qs_scatter - Assign a scattered queues to VSI - * @vsi: the VSI getting queues + * __ice_vsi_get_qs_sc - Assign a scattered queues from PF to VSI + * @qs_cfg: gathered variables needed for PF->VSI queues assignment * - * Return 0 on success and a negative value on error + * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap */ -static int ice_vsi_get_qs_scatter(struct ice_vsi *vsi) +static int __ice_vsi_get_qs_sc(struct ice_qs_cfg *qs_cfg) { - struct ice_pf *pf = vsi->back; int i, index = 0; - mutex_lock(&pf->avail_q_mutex); - - if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) { - for (i = 0; i < vsi->alloc_txq; i++) { - index = find_next_zero_bit(pf->avail_txqs, - ICE_MAX_TXQS, index); - if (index < ICE_MAX_TXQS) { - set_bit(index, pf->avail_txqs); - vsi->txq_map[i] = index; - } else { - goto err_scatter_tx; - } - } - } - - if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) { - for (i = 0; i < vsi->alloc_rxq; i++) { - index = find_next_zero_bit(pf->avail_rxqs, - ICE_MAX_RXQS, index); - if (index < ICE_MAX_RXQS) { - set_bit(index, pf->avail_rxqs); - vsi->rxq_map[i] = index; - } else { - goto err_scatter_rx; - } - } + mutex_lock(qs_cfg->qs_mutex); + for (i = 0; i < qs_cfg->q_count; i++) { + index = find_next_zero_bit(qs_cfg->pf_map, + qs_cfg->pf_map_size, index); + if (index >= qs_cfg->pf_map_size) + goto err_scatter; + set_bit(index, qs_cfg->pf_map); + qs_cfg->vsi_map[i + qs_cfg->vsi_map_offset] = index; } + mutex_unlock(qs_cfg->qs_mutex); - mutex_unlock(&pf->avail_q_mutex); return 0; - -err_scatter_rx: - /* unflag any queues we have grabbed (i is failed position) */ +err_scatter: for (index = 0; index < i; index++) { - clear_bit(vsi->rxq_map[index], pf->avail_rxqs); - vsi->rxq_map[index] = 0; - } - i = vsi->alloc_txq; -err_scatter_tx: - /* i is either position of failed attempt or vsi->alloc_txq */ - for (index = 0; index < i; index++) { - clear_bit(vsi->txq_map[index], pf->avail_txqs); - vsi->txq_map[index] = 0; + clear_bit(qs_cfg->vsi_map[index], qs_cfg->pf_map); + qs_cfg->vsi_map[index + qs_cfg->vsi_map_offset] = 0; } + mutex_unlock(qs_cfg->qs_mutex); - mutex_unlock(&pf->avail_q_mutex); return -ENOMEM; } +/** + * __ice_vsi_get_qs - helper function for assigning queues from PF to VSI + * @qs_cfg: gathered variables needed for PF->VSI queues assignment + * + * This is an internal function for assigning queues from the PF to VSI and + * initially tries to find contiguous space. If it is not successful to find + * contiguous space, then it tries with the scatter approach. + * + * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap + */ +static int __ice_vsi_get_qs(struct ice_qs_cfg *qs_cfg) +{ + int ret = 0; + + ret = __ice_vsi_get_qs_contig(qs_cfg); + if (ret) { + /* contig failed, so try with scatter approach */ + qs_cfg->mapping_mode = ICE_VSI_MAP_SCATTER; + qs_cfg->q_count = min_t(u16, qs_cfg->q_count, + qs_cfg->scatter_count); + ret = __ice_vsi_get_qs_sc(qs_cfg); + } + return ret; +} + /** * ice_vsi_get_qs - Assign queues from PF to VSI * @vsi: the VSI to assign queues to @@ -625,25 +604,35 @@ err_scatter_tx: */ static int ice_vsi_get_qs(struct ice_vsi *vsi) { + struct ice_pf *pf = vsi->back; + struct ice_qs_cfg tx_qs_cfg = { + .qs_mutex = &pf->avail_q_mutex, + .pf_map = pf->avail_txqs, + .pf_map_size = ICE_MAX_TXQS, + .q_count = vsi->alloc_txq, + .scatter_count = ICE_MAX_SCATTER_TXQS, + .vsi_map = vsi->txq_map, + .vsi_map_offset = 0, + .mapping_mode = vsi->tx_mapping_mode + }; + struct ice_qs_cfg rx_qs_cfg = { + .qs_mutex = &pf->avail_q_mutex, + .pf_map = pf->avail_rxqs, + .pf_map_size = ICE_MAX_RXQS, + .q_count = vsi->alloc_rxq, + .scatter_count = ICE_MAX_SCATTER_RXQS, + .vsi_map = vsi->rxq_map, + .vsi_map_offset = 0, + .mapping_mode = vsi->rx_mapping_mode + }; int ret = 0; vsi->tx_mapping_mode = ICE_VSI_MAP_CONTIG; vsi->rx_mapping_mode = ICE_VSI_MAP_CONTIG; - /* NOTE: ice_vsi_get_qs_contig() will set the Rx/Tx mapping - * modes individually to scatter if assigning contiguous queues - * to Rx or Tx fails - */ - ret = ice_vsi_get_qs_contig(vsi); - if (ret < 0) { - if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) - vsi->alloc_txq = max_t(u16, vsi->alloc_txq, - ICE_MAX_SCATTER_TXQS); - if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) - vsi->alloc_rxq = max_t(u16, vsi->alloc_rxq, - ICE_MAX_SCATTER_RXQS); - ret = ice_vsi_get_qs_scatter(vsi); - } + ret = __ice_vsi_get_qs(&tx_qs_cfg); + if (!ret) + ret = __ice_vsi_get_qs(&rx_qs_cfg); return ret; } @@ -1614,11 +1603,14 @@ setup_rings: /** * ice_vsi_cfg_txqs - Configure the VSI for Tx * @vsi: the VSI being configured + * @rings: Tx ring array to be configured + * @offset: offset within vsi->txq_map * * Return 0 on success and a negative value on error * Configure the Tx VSI for operation. */ -int ice_vsi_cfg_txqs(struct ice_vsi *vsi) +static int +ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings, int offset) { struct ice_aqc_add_tx_qgrp *qg_buf; struct ice_aqc_add_txqs_perq *txq; @@ -1626,7 +1618,7 @@ int ice_vsi_cfg_txqs(struct ice_vsi *vsi) u8 num_q_grps, q_idx = 0; enum ice_status status; u16 buf_len, i, pf_q; - int err = 0, tc = 0; + int err = 0, tc; buf_len = sizeof(struct ice_aqc_add_tx_qgrp); qg_buf = devm_kzalloc(&pf->pdev->dev, buf_len, GFP_KERNEL); @@ -1644,9 +1636,8 @@ int ice_vsi_cfg_txqs(struct ice_vsi *vsi) for (i = 0; i < vsi->tc_cfg.tc_info[tc].qcount_tx; i++) { struct ice_tlan_ctx tlan_ctx = { 0 }; - pf_q = vsi->txq_map[q_idx]; - ice_setup_tx_ctx(vsi->tx_rings[q_idx], &tlan_ctx, - pf_q); + pf_q = vsi->txq_map[q_idx + offset]; + ice_setup_tx_ctx(rings[q_idx], &tlan_ctx, pf_q); /* copy context contents into the qg_buf */ qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q); ice_set_ctx((u8 *)&tlan_ctx, qg_buf->txqs[0].txq_ctx, @@ -1655,7 +1646,7 @@ int ice_vsi_cfg_txqs(struct ice_vsi *vsi) /* init queue specific tail reg. It is referred as * transmit comm scheduler queue doorbell. */ - vsi->tx_rings[q_idx]->tail = + rings[q_idx]->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q); status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc, num_q_grps, qg_buf, buf_len, @@ -1674,7 +1665,7 @@ int ice_vsi_cfg_txqs(struct ice_vsi *vsi) */ txq = &qg_buf->txqs[0]; if (pf_q == le16_to_cpu(txq->txq_id)) - vsi->tx_rings[q_idx]->txq_teid = + rings[q_idx]->txq_teid = le32_to_cpu(txq->q_teid); q_idx++; @@ -1685,6 +1676,18 @@ err_cfg_txqs: return err; } +/** + * ice_vsi_cfg_lan_txqs - Configure the VSI for Tx + * @vsi: the VSI being configured + * + * Return 0 on success and a negative value on error + * Configure the Tx VSI for operation. + */ +int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi) +{ + return ice_vsi_cfg_txqs(vsi, vsi->tx_rings, 0); +} + /** * ice_intrl_usec_to_reg - convert interrupt rate limit to register value * @intrl: interrupt rate limit in usecs @@ -1897,9 +1900,12 @@ int ice_vsi_stop_rx_rings(struct ice_vsi *vsi) * @vsi: the VSI being configured * @rst_src: reset source * @rel_vmvf_num: Relative id of VF/VM + * @rings: Tx ring array to be stopped + * @offset: offset within vsi->txq_map */ -int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, - u16 rel_vmvf_num) +static int +ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, + u16 rel_vmvf_num, struct ice_ring **rings, int offset) { struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; @@ -1927,19 +1933,18 @@ int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, ice_for_each_txq(vsi, i) { u16 v_idx; - if (!vsi->tx_rings || !vsi->tx_rings[i] || - !vsi->tx_rings[i]->q_vector) { + if (!rings || !rings[i] || !rings[i]->q_vector) { err = -EINVAL; goto err_out; } - q_ids[i] = vsi->txq_map[i]; - q_teids[i] = vsi->tx_rings[i]->txq_teid; + q_ids[i] = vsi->txq_map[i + offset]; + q_teids[i] = rings[i]->txq_teid; /* clear cause_ena bit for disabled queues */ - val = rd32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx)); + val = rd32(hw, QINT_TQCTL(rings[i]->reg_idx)); val &= ~QINT_TQCTL_CAUSE_ENA_M; - wr32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx), val); + wr32(hw, QINT_TQCTL(rings[i]->reg_idx), val); /* software is expected to wait for 100 ns */ ndelay(100); @@ -1947,7 +1952,7 @@ int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, /* trigger a software interrupt for the vector associated to * the queue to schedule NAPI handler */ - v_idx = vsi->tx_rings[i]->q_vector->v_idx; + v_idx = rings[i]->q_vector->v_idx; wr32(hw, GLINT_DYN_CTL(vsi->hw_base_vector + v_idx), GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M); } @@ -1976,6 +1981,19 @@ err_alloc_q_ids: return err; } +/** + * ice_vsi_stop_lan_tx_rings - Disable LAN Tx rings + * @vsi: the VSI being configured + * @rst_src: reset source + * @rel_vmvf_num: Relative id of VF/VM + */ +int ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, + enum ice_disq_rst_src rst_src, u16 rel_vmvf_num) +{ + return ice_vsi_stop_tx_rings(vsi, rst_src, rel_vmvf_num, vsi->tx_rings, + 0); +} + /** * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI * @vsi: VSI to enable or disable VLAN pruning on diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 3831b4f0960a..7988a53729a9 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -15,7 +15,7 @@ void ice_update_eth_stats(struct ice_vsi *vsi); int ice_vsi_cfg_rxqs(struct ice_vsi *vsi); -int ice_vsi_cfg_txqs(struct ice_vsi *vsi); +int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi); void ice_vsi_cfg_msix(struct ice_vsi *vsi); @@ -31,7 +31,8 @@ int ice_vsi_start_rx_rings(struct ice_vsi *vsi); int ice_vsi_stop_rx_rings(struct ice_vsi *vsi); -int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, +int +ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, u16 rel_vmvf_num); int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index e36db981f047..093708b5c0ef 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2546,7 +2546,8 @@ static int ice_vsi_cfg(struct ice_vsi *vsi) if (err) return err; } - err = ice_vsi_cfg_txqs(vsi); + + err = ice_vsi_cfg_lan_txqs(vsi); if (!err) err = ice_vsi_cfg_rxqs(vsi); @@ -3040,7 +3041,8 @@ int ice_down(struct ice_vsi *vsi) } ice_vsi_dis_irq(vsi); - tx_err = ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, 0); + + tx_err = ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0); if (tx_err) netdev_err(vsi->netdev, "Failed stop Tx rings, VSI %d error %d\n", diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 05ff4f910649..80b50e67cbef 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -224,13 +224,15 @@ void ice_free_vfs(struct ice_pf *pf) /* Avoid wait time by stopping all VFs at the same time */ for (i = 0; i < pf->num_alloc_vfs; i++) { + struct ice_vsi *vsi; + if (!test_bit(ICE_VF_STATE_ENA, pf->vf[i].vf_states)) continue; + vsi = pf->vsi[pf->vf[i].lan_vsi_idx]; /* stop rings without wait time */ - ice_vsi_stop_tx_rings(pf->vsi[pf->vf[i].lan_vsi_idx], - ICE_NO_RESET, i); - ice_vsi_stop_rx_rings(pf->vsi[pf->vf[i].lan_vsi_idx]); + ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, i); + ice_vsi_stop_rx_rings(vsi); clear_bit(ICE_VF_STATE_ENA, pf->vf[i].vf_states); } @@ -831,6 +833,7 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) { struct ice_pf *pf = vf->pf; struct ice_hw *hw = &pf->hw; + struct ice_vsi *vsi; bool rsd = false; u32 reg; int i; @@ -843,17 +846,18 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) ice_trigger_vf_reset(vf, is_vflr); + vsi = pf->vsi[vf->lan_vsi_idx]; + if (test_bit(ICE_VF_STATE_ENA, vf->vf_states)) { - ice_vsi_stop_tx_rings(pf->vsi[vf->lan_vsi_idx], ICE_VF_RESET, - vf->vf_id); - ice_vsi_stop_rx_rings(pf->vsi[vf->lan_vsi_idx]); + ice_vsi_stop_lan_tx_rings(vsi, ICE_VF_RESET, vf->vf_id); + ice_vsi_stop_rx_rings(vsi); clear_bit(ICE_VF_STATE_ENA, vf->vf_states); } else { /* Call Disable LAN Tx queue AQ call even when queues are not * enabled. This is needed for successful completiom of VFR */ - ice_dis_vsi_txq(pf->vsi[vf->lan_vsi_idx]->port_info, 0, - NULL, NULL, ICE_VF_RESET, vf->vf_id, NULL); + ice_dis_vsi_txq(vsi->port_info, 0, NULL, NULL, ICE_VF_RESET, + vf->vf_id, NULL); } /* poll VPGEN_VFRSTAT reg to make sure @@ -1614,7 +1618,7 @@ static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) goto error_param; } - if (ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, vf->vf_id)) { + if (ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, vf->vf_id)) { dev_err(&vsi->back->pdev->dev, "Failed to stop tx rings on VSI %d\n", vsi->vsi_num); @@ -1784,7 +1788,7 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) vsi->num_txq = qci->num_queue_pairs; vsi->num_rxq = qci->num_queue_pairs; - if (!ice_vsi_cfg_txqs(vsi) && !ice_vsi_cfg_rxqs(vsi)) + if (!ice_vsi_cfg_lan_txqs(vsi) && !ice_vsi_cfg_rxqs(vsi)) aq_ret = 0; else aq_ret = ICE_ERR_PARAM; -- cgit v1.2.3 From 9be1d6f8c33731acd67586a4e40c0f3d56a23366 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Dec 2018 10:03:28 -0800 Subject: ice: Move aggregator list into ice_hw instance The aggregator list needs to be preserved for use after a reset. This patch moves it out of the port_info instance and into the ice_hw instance. Signed-off-by: Tarun Singh Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 2 ++ drivers/net/ethernet/intel/ice/ice_sched.c | 34 ++++++++++++++++++----------- drivers/net/ethernet/intel/ice/ice_sched.h | 2 ++ drivers/net/ethernet/intel/ice/ice_type.h | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 2bcd8230d35e..19695749f903 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -750,6 +750,7 @@ enum ice_status ice_init_hw(struct ice_hw *hw) status = ICE_ERR_CFG; goto err_unroll_sched; } + INIT_LIST_HEAD(&hw->agg_list); status = ice_init_fltr_mgmt_struct(hw); if (status) @@ -800,6 +801,7 @@ void ice_deinit_hw(struct ice_hw *hw) ice_cleanup_fltr_mgmt_struct(hw); ice_sched_cleanup_all(hw); + ice_sched_clear_agg(hw); if (hw->port_info) { devm_kfree(ice_hw_to_dev(hw), hw->port_info); diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index 99d51990bd54..fb38e8be1e2e 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -561,23 +561,18 @@ ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids, } /** - * ice_sched_clear_tx_topo - clears the schduler tree nodes - * @pi: port information structure + * ice_sched_clear_agg - clears the agg related information + * @hw: pointer to the hardware structure * - * This function removes all the nodes from HW as well as from SW DB. + * This function removes agg list and free up agg related memory + * previously allocated. */ -static void ice_sched_clear_tx_topo(struct ice_port_info *pi) +void ice_sched_clear_agg(struct ice_hw *hw) { struct ice_sched_agg_info *agg_info; struct ice_sched_agg_info *atmp; - struct ice_hw *hw; - - if (!pi) - return; - hw = pi->hw; - - list_for_each_entry_safe(agg_info, atmp, &pi->agg_list, list_entry) { + list_for_each_entry_safe(agg_info, atmp, &hw->agg_list, list_entry) { struct ice_sched_agg_vsi_info *agg_vsi_info; struct ice_sched_agg_vsi_info *vtmp; @@ -586,8 +581,21 @@ static void ice_sched_clear_tx_topo(struct ice_port_info *pi) list_del(&agg_vsi_info->list_entry); devm_kfree(ice_hw_to_dev(hw), agg_vsi_info); } + list_del(&agg_info->list_entry); + devm_kfree(ice_hw_to_dev(hw), agg_info); } +} +/** + * ice_sched_clear_tx_topo - clears the scheduler tree nodes + * @pi: port information structure + * + * This function removes all the nodes from HW as well as from SW DB. + */ +static void ice_sched_clear_tx_topo(struct ice_port_info *pi) +{ + if (!pi) + return; if (pi->root) { ice_free_sched_node(pi, pi->root); pi->root = NULL; @@ -1005,7 +1013,6 @@ enum ice_status ice_sched_init_port(struct ice_port_info *pi) /* initialize the port for handling the scheduler tree */ pi->port_state = ICE_SCHED_PORT_STATE_READY; mutex_init(&pi->sched_lock); - INIT_LIST_HEAD(&pi->agg_list); err_init_port: if (status && pi->root) { @@ -1588,7 +1595,8 @@ ice_sched_rm_agg_vsi_info(struct ice_port_info *pi, u16 vsi_handle) struct ice_sched_agg_info *agg_info; struct ice_sched_agg_info *atmp; - list_for_each_entry_safe(agg_info, atmp, &pi->agg_list, list_entry) { + list_for_each_entry_safe(agg_info, atmp, &pi->hw->agg_list, + list_entry) { struct ice_sched_agg_vsi_info *agg_vsi_info; struct ice_sched_agg_vsi_info *vtmp; diff --git a/drivers/net/ethernet/intel/ice/ice_sched.h b/drivers/net/ethernet/intel/ice/ice_sched.h index da5b4c166da8..bee8221ad146 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.h +++ b/drivers/net/ethernet/intel/ice/ice_sched.h @@ -28,6 +28,8 @@ enum ice_status ice_sched_init_port(struct ice_port_info *pi); enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw); void ice_sched_clear_port(struct ice_port_info *pi); void ice_sched_cleanup_all(struct ice_hw *hw); +void ice_sched_clear_agg(struct ice_hw *hw); + struct ice_sched_node * ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid); enum ice_status diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 0ea428104215..a078e2c98871 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -272,7 +272,6 @@ struct ice_port_info { struct ice_mac_info mac; struct ice_phy_info phy; struct mutex sched_lock; /* protect access to TXSched tree */ - struct list_head agg_list; /* lists all aggregator */ u8 lport; #define ICE_LPORT_MASK 0xff u8 is_vf; @@ -326,6 +325,7 @@ struct ice_hw { u8 max_cgds; u8 sw_entry_point_layer; u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM]; + struct list_head agg_list; /* lists all aggregator */ struct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI]; u8 evb_veb; /* true for VEB, false for VEPA */ -- cgit v1.2.3 From 63f545ed1285a5f904c260ff22c958609c3c11c5 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Dec 2018 10:03:29 -0800 Subject: ice: Add support for adaptive interrupt moderation Currently the driver does not support adaptive/dynamic interrupt moderation. This patch adds support for this. Also, adaptive/dynamic interrupt moderation is turned on by default upon driver load. In order to support adaptive interrupt moderation, two functions were added, ice_update_itr() and ice_itr_divisor(). These are used to determine the current packet load and to determine a divisor based on link speed respectively. This patch also adds the ICE_ITR_GRAN_S define that is used in the hot-path when setting a new ITR value. The shift is used to pet two birds with one hand, set the ITR value while re-enabling the interrupt. Also, the ICE_ITR_GRAN_S is defined as 1 because the device has a ITR granularity of 2usecs. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_hw_autogen.h | 1 + drivers/net/ethernet/intel/ice/ice_lib.c | 24 ++++++--- drivers/net/ethernet/intel/ice/ice_main.c | 23 +++++++-- drivers/net/ethernet/intel/ice/ice_txrx.c | 65 ++++++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_txrx.h | 30 +++++++----- 5 files changed, 120 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 5507928c8fbe..f9a38f2cd470 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -110,6 +110,7 @@ #define GLINT_DYN_CTL_CLEARPBA_M BIT(1) #define GLINT_DYN_CTL_SWINT_TRIG_M BIT(2) #define GLINT_DYN_CTL_ITR_INDX_S 3 +#define GLINT_DYN_CTL_INTERVAL_S 5 #define GLINT_DYN_CTL_SW_ITR_INDX_M ICE_M(0x3, 25) #define GLINT_DYN_CTL_INTENA_MSK_M BIT(31) #define GLINT_ITR(_i, _INT) (0x00154000 + ((_i) * 8192 + (_INT) * 4)) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index a1f523a9d39d..27c3760ae5cb 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1717,22 +1717,34 @@ static u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran) static void ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector, u16 vector) { - u8 itr_gran = hw->itr_gran; - if (q_vector->num_ring_rx) { struct ice_ring_container *rc = &q_vector->rx; - rc->itr = ITR_TO_REG(ICE_DFLT_RX_ITR, itr_gran); + /* if this value is set then don't overwrite with default */ + if (!rc->itr_setting) + rc->itr_setting = ICE_DFLT_RX_ITR; + + rc->target_itr = ITR_TO_REG(rc->itr_setting); + rc->next_update = jiffies + 1; + rc->current_itr = rc->target_itr; rc->latency_range = ICE_LOW_LATENCY; - wr32(hw, GLINT_ITR(rc->itr_idx, vector), rc->itr); + wr32(hw, GLINT_ITR(rc->itr_idx, vector), + ITR_REG_ALIGN(rc->current_itr) >> ICE_ITR_GRAN_S); } if (q_vector->num_ring_tx) { struct ice_ring_container *rc = &q_vector->tx; - rc->itr = ITR_TO_REG(ICE_DFLT_TX_ITR, itr_gran); + /* if this value is set then don't overwrite with default */ + if (!rc->itr_setting) + rc->itr_setting = ICE_DFLT_TX_ITR; + + rc->target_itr = ITR_TO_REG(rc->itr_setting); + rc->next_update = jiffies + 1; + rc->current_itr = rc->target_itr; rc->latency_range = ICE_LOW_LATENCY; - wr32(hw, GLINT_ITR(rc->itr_idx, vector), rc->itr); + wr32(hw, GLINT_ITR(rc->itr_idx, vector), + ITR_REG_ALIGN(rc->current_itr) >> ICE_ITR_GRAN_S); } } diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 093708b5c0ef..e59f8b29af49 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1389,7 +1389,6 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; int oicr_idx, err = 0; - u8 itr_gran; u32 val; if (!pf->int_name[0]) @@ -1453,10 +1452,8 @@ skip_req_irq: PFINT_MBX_CTL_CAUSE_ENA_M); wr32(hw, PFINT_MBX_CTL, val); - itr_gran = hw->itr_gran; - wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->hw_oicr_idx), - ITR_TO_REG(ICE_ITR_8K, itr_gran)); + ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S); ice_flush(hw); ice_irq_dynamic_ena(hw, NULL, NULL); @@ -1997,6 +1994,23 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf) return 0; } +/** + * ice_verify_itr_gran - verify driver's assumption of ITR granularity + * @pf: pointer to the PF structure + * + * There is no error returned here because the driver will be able to handle a + * different ITR granularity, but interrupt moderation will not be accurate if + * the driver's assumptions are not verified. This assumption is made so we can + * use constants in the hot path instead of accessing structure members. + */ +static void ice_verify_itr_gran(struct ice_pf *pf) +{ + if (pf->hw.itr_gran != (ICE_ITR_GRAN_S << 1)) + dev_warn(&pf->pdev->dev, + "%d ITR granularity assumption is invalid, actual ITR granularity is %d. Interrupt moderation will be inaccurate!\n", + (ICE_ITR_GRAN_S << 1), pf->hw.itr_gran); +} + /** * ice_verify_cacheline_size - verify driver's assumption of 64 Byte cache lines * @pf: pointer to the PF structure @@ -2163,6 +2177,7 @@ static int ice_probe(struct pci_dev *pdev, mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period)); ice_verify_cacheline_size(pf); + ice_verify_itr_gran(pf); return 0; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 49fc38094185..384ac5c82e00 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1052,6 +1052,69 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) return failure ? budget : (int)total_rx_pkts; } +/** + * ice_buildreg_itr - build value for writing to the GLINT_DYN_CTL register + * @itr_idx: interrupt throttling index + * @reg_itr: interrupt throttling value adjusted based on ITR granularity + */ +static u32 ice_buildreg_itr(int itr_idx, u16 reg_itr) +{ + return GLINT_DYN_CTL_INTENA_M | GLINT_DYN_CTL_CLEARPBA_M | + (itr_idx << GLINT_DYN_CTL_ITR_INDX_S) | + (reg_itr << GLINT_DYN_CTL_INTERVAL_S); +} + +/** + * ice_update_ena_itr - Update ITR and re-enable MSIX interrupt + * @vsi: the VSI associated with the q_vector + * @q_vector: q_vector for which ITR is being updated and interrupt enabled + */ +static void +ice_update_ena_itr(struct ice_vsi *vsi, struct ice_q_vector *q_vector) +{ + struct ice_hw *hw = &vsi->back->hw; + struct ice_ring_container *rc; + u32 itr_val; + + /* This block of logic allows us to get away with only updating + * one ITR value with each interrupt. The idea is to perform a + * pseudo-lazy update with the following criteria. + * + * 1. Rx is given higher priority than Tx if both are in same state + * 2. If we must reduce an ITR that is given highest priority. + * 3. We then give priority to increasing ITR based on amount. + */ + if (q_vector->rx.target_itr < q_vector->rx.current_itr) { + rc = &q_vector->rx; + /* Rx ITR needs to be reduced, this is highest priority */ + itr_val = ice_buildreg_itr(rc->itr_idx, rc->target_itr); + rc->current_itr = rc->target_itr; + } else if ((q_vector->tx.target_itr < q_vector->tx.current_itr) || + ((q_vector->rx.target_itr - q_vector->rx.current_itr) < + (q_vector->tx.target_itr - q_vector->tx.current_itr))) { + rc = &q_vector->tx; + /* Tx ITR needs to be reduced, this is second priority + * Tx ITR needs to be increased more than Rx, fourth priority + */ + itr_val = ice_buildreg_itr(rc->itr_idx, rc->target_itr); + rc->current_itr = rc->target_itr; + } else if (q_vector->rx.current_itr != q_vector->rx.target_itr) { + rc = &q_vector->rx; + /* Rx ITR needs to be increased, third priority */ + itr_val = ice_buildreg_itr(rc->itr_idx, rc->target_itr); + rc->current_itr = rc->target_itr; + } else { + /* Still have to re-enable the interrupts */ + itr_val = ice_buildreg_itr(ICE_ITR_NONE, 0); + } + + if (!test_bit(__ICE_DOWN, vsi->state)) { + int vector = vsi->hw_base_vector + q_vector->v_idx; + + wr32(hw, GLINT_DYN_CTL(vector), itr_val); + } +} + /** * ice_napi_poll - NAPI polling Rx/Tx cleanup routine * @napi: napi struct with our devices info in it @@ -1108,7 +1171,7 @@ int ice_napi_poll(struct napi_struct *napi, int budget) */ if (likely(napi_complete_done(napi, work_done))) if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) - ice_irq_dynamic_ena(&vsi->back->hw, vsi, q_vector); + ice_update_ena_itr(vsi, q_vector); return min(work_done, budget - 1); } diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 75d0eaf6c9dd..aa646002d653 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -116,16 +116,15 @@ enum ice_rx_dtype { /* indices into GLINT_ITR registers */ #define ICE_RX_ITR ICE_IDX_ITR0 #define ICE_TX_ITR ICE_IDX_ITR1 -#define ICE_ITR_DYNAMIC 0x8000 /* use top bit as a flag */ -#define ICE_ITR_8K 125 +#define ICE_ITR_8K 124 #define ICE_ITR_20K 50 -#define ICE_DFLT_TX_ITR ICE_ITR_20K -#define ICE_DFLT_RX_ITR ICE_ITR_20K -/* apply ITR granularity translation to program the register. itr_gran is either - * 2 or 4 usecs so we need to divide by 2 first then shift by that value - */ -#define ITR_TO_REG(val, itr_gran) (((val) & ~ICE_ITR_DYNAMIC) >> \ - ((itr_gran) / 2)) +#define ICE_DFLT_TX_ITR (ICE_ITR_20K | ICE_ITR_DYNAMIC) +#define ICE_DFLT_RX_ITR (ICE_ITR_20K | ICE_ITR_DYNAMIC) +#define ICE_ITR_DYNAMIC 0x8000 /* used as flag for itr_setting */ +#define ITR_TO_REG(setting) ((setting) & ~ICE_ITR_DYNAMIC) +#define ICE_ITR_GRAN_S 1 /* Assume ITR granularity is 2us */ +#define ICE_ITR_MASK 0x1FFE /* ITR register value alignment mask */ +#define ITR_REG_ALIGN(setting) __ALIGN_MASK(setting, ~ICE_ITR_MASK) #define ICE_DFLT_INTRL 0 @@ -180,13 +179,20 @@ enum ice_latency_range { }; struct ice_ring_container { - /* array of pointers to rings */ + /* head of linked-list of rings */ struct ice_ring *ring; + unsigned long next_update; /* jiffies value of next queue update */ unsigned int total_bytes; /* total bytes processed this int */ unsigned int total_pkts; /* total packets processed this int */ enum ice_latency_range latency_range; - int itr_idx; /* index in the interrupt vector */ - u16 itr; + int itr_idx; /* index in the interrupt vector */ + u16 target_itr; /* value in usecs divided by the hw->itr_gran */ + u16 current_itr; /* value in usecs divided by the hw->itr_gran */ + /* high bit set means dynamic ITR, rest is used to store user + * readable ITR value in usecs and must be converted before programming + * to a register. + */ + u16 itr_setting; }; /* iterator for handling rings in ring container */ -- cgit v1.2.3 From 9cb76a6aa1a9524866ec1558f08d044506b707fa Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 09:36:01 -0600 Subject: mtd: gen_probe: Use struct_size() in kmalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kmalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kmalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Boris Brezillon --- drivers/mtd/chips/gen_probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index 837b04ab96a9..839ed40625d6 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -135,7 +135,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi * our caller, and copy the appropriate data into them. */ - retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL); + retcfi = kmalloc(struct_size(retcfi, chips, cfi.numchips), GFP_KERNEL); if (!retcfi) { kfree(cfi.cfiq); -- cgit v1.2.3 From 04b4c06caf2b810f0ce4822f6611ed35326ca11a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 09:52:44 -0600 Subject: mtd: cfi: cmdset_0001: Use struct_size() in kmalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kmalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kmalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Boris Brezillon --- drivers/mtd/chips/cfi_cmdset_0001.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 6e8e7b1bb34b..79a53cb8507b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -756,7 +756,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, } numvirtchips = cfi->numchips * numparts; - newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL); + newcfi = kmalloc(struct_size(newcfi, chips, numvirtchips), + GFP_KERNEL); if (!newcfi) return -ENOMEM; shared = kmalloc_array(cfi->numchips, -- cgit v1.2.3 From 2037f9d8c242af5d549dd5ba32ff1ec1f49ceaad Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 15:09:46 -0600 Subject: mtd: lpddr: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Boris Brezillon --- drivers/mtd/lpddr/qinfo_probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/lpddr/qinfo_probe.c b/drivers/mtd/lpddr/qinfo_probe.c index 69f2112340b1..175bdc3b72f4 100644 --- a/drivers/mtd/lpddr/qinfo_probe.c +++ b/drivers/mtd/lpddr/qinfo_probe.c @@ -181,8 +181,8 @@ static struct lpddr_private *lpddr_probe_chip(struct map_info *map) lpddr.numchips = 1; numvirtchips = lpddr.numchips * lpddr.qinfo->HWPartsNum; - retlpddr = kzalloc(sizeof(struct lpddr_private) + - numvirtchips * sizeof(struct flchip), GFP_KERNEL); + retlpddr = kzalloc(struct_size(retlpddr, chips, numvirtchips), + GFP_KERNEL); if (!retlpddr) return NULL; -- cgit v1.2.3 From 67fe64d78c437d3f5a280a074e8467fa9b16216d Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Dec 2018 10:03:30 -0800 Subject: ice: Implement getting and setting ethtool coalesce This patch includes the following ethtool operations: 1. get_coalesce 2. set_coalesce 3. get_per_q_coalesce 4. set_per_q_coalesce Each ITR value (current_itr/target_itr) are stored on a per ice_ring_container basis. This is because each valid ice_ring_container can have 1 or more rings that are tied to the same q_vector ITR index. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 3 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 256 +++++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_txrx.h | 2 + 3 files changed, 261 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index ffe4ffe16912..ac8bf7491d08 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -110,6 +110,9 @@ extern const char ice_drv_ver[]; #define ice_for_each_alloc_rxq(vsi, i) \ for ((i) = 0; (i) < (vsi)->alloc_rxq; (i)++) +#define ice_for_each_q_vector(vsi, i) \ + for ((i) = 0; (i) < (vsi)->num_q_vectors; (i)++) + struct ice_tc_info { u16 qoffset; u16 qcount_tx; diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 24c8aeaea2d5..02316e32dfb3 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -1823,6 +1823,258 @@ static int ice_set_rxfh(struct net_device *netdev, const u32 *indir, return 0; } +enum ice_container_type { + ICE_RX_CONTAINER, + ICE_TX_CONTAINER, +}; + +/** + * ice_get_rc_coalesce - get ITR values for specific ring container + * @ec: ethtool structure to fill with driver's coalesce settings + * @c_type: container type, RX or TX + * @rc: ring container that the ITR values will come from + * + * Query the device for ice_ring_container specific ITR values. This is + * done per ice_ring_container because each q_vector can have 1 or more rings + * and all of said ring(s) will have the same ITR values. + * + * Returns 0 on success, negative otherwise. + */ +static int +ice_get_rc_coalesce(struct ethtool_coalesce *ec, enum ice_container_type c_type, + struct ice_ring_container *rc) +{ + struct ice_pf *pf = rc->ring->vsi->back; + + switch (c_type) { + case ICE_RX_CONTAINER: + ec->use_adaptive_rx_coalesce = ITR_IS_DYNAMIC(rc->itr_setting); + ec->rx_coalesce_usecs = rc->itr_setting & ~ICE_ITR_DYNAMIC; + break; + case ICE_TX_CONTAINER: + ec->use_adaptive_tx_coalesce = ITR_IS_DYNAMIC(rc->itr_setting); + ec->tx_coalesce_usecs = rc->itr_setting & ~ICE_ITR_DYNAMIC; + break; + default: + dev_dbg(&pf->pdev->dev, "Invalid c_type %d\n", c_type); + return -EINVAL; + } + + return 0; +} + +/** + * __ice_get_coalesce - get ITR/INTRL values for the device + * @netdev: pointer to the netdev associated with this query + * @ec: ethtool structure to fill with driver's coalesce settings + * @q_num: queue number to get the coalesce settings for + */ +static int +__ice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, + int q_num) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + int tx = -EINVAL, rx = -EINVAL; + struct ice_vsi *vsi = np->vsi; + + if (q_num < 0) { + rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, + &vsi->rx_rings[0]->q_vector->rx); + tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, + &vsi->tx_rings[0]->q_vector->tx); + + goto update_coalesced_frames; + } + + if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { + rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, + &vsi->rx_rings[q_num]->q_vector->rx); + tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, + &vsi->tx_rings[q_num]->q_vector->tx); + } else if (q_num < vsi->num_rxq) { + rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, + &vsi->rx_rings[q_num]->q_vector->rx); + } else if (q_num < vsi->num_txq) { + tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, + &vsi->tx_rings[q_num]->q_vector->tx); + } else { + /* q_num is invalid for both Rx and Tx queues */ + return -EINVAL; + } + +update_coalesced_frames: + /* either q_num is invalid for both Rx and Tx queues or setting coalesce + * failed completely + */ + if (tx && rx) + return -EINVAL; + + if (q_num < vsi->num_txq) + ec->tx_max_coalesced_frames_irq = vsi->work_lmt; + + if (q_num < vsi->num_rxq) + ec->rx_max_coalesced_frames_irq = vsi->work_lmt; + + return 0; +} + +static int +ice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) +{ + return __ice_get_coalesce(netdev, ec, -1); +} + +static int ice_get_per_q_coalesce(struct net_device *netdev, u32 q_num, + struct ethtool_coalesce *ec) +{ + return __ice_get_coalesce(netdev, ec, q_num); +} + +/** + * ice_set_rc_coalesce - set ITR values for specific ring container + * @c_type: container type, RX or TX + * @ec: ethtool structure from user to update ITR settings + * @rc: ring container that the ITR values will come from + * @vsi: VSI associated to the ring container + * + * Set specific ITR values. This is done per ice_ring_container because each + * q_vector can have 1 or more rings and all of said ring(s) will have the same + * ITR values. + * + * Returns 0 on success, negative otherwise. + */ +static int +ice_set_rc_coalesce(enum ice_container_type c_type, struct ethtool_coalesce *ec, + struct ice_ring_container *rc, struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + u16 itr_setting; + + if (!rc->ring) + return -EINVAL; + + itr_setting = rc->itr_setting & ~ICE_ITR_DYNAMIC; + + switch (c_type) { + case ICE_RX_CONTAINER: + if (ec->rx_coalesce_usecs != itr_setting && + ec->use_adaptive_rx_coalesce) { + netdev_info(vsi->netdev, + "Rx interrupt throttling cannot be changed if adaptive-rx is enabled\n"); + return -EINVAL; + } + + if (ec->rx_coalesce_usecs > ICE_ITR_MAX) { + netdev_info(vsi->netdev, + "Invalid value, rx-usecs range is 0-%d\n", + ICE_ITR_MAX); + return -EINVAL; + } + + if (ec->use_adaptive_rx_coalesce) { + rc->itr_setting |= ICE_ITR_DYNAMIC; + } else { + rc->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs); + rc->target_itr = ITR_TO_REG(rc->itr_setting); + } + break; + case ICE_TX_CONTAINER: + if (ec->tx_coalesce_usecs != itr_setting && + ec->use_adaptive_tx_coalesce) { + netdev_info(vsi->netdev, + "Tx interrupt throttling cannot be changed if adaptive-tx is enabled\n"); + return -EINVAL; + } + + if (ec->tx_coalesce_usecs > ICE_ITR_MAX) { + netdev_info(vsi->netdev, + "Invalid value, tx-usecs range is 0-%d\n", + ICE_ITR_MAX); + return -EINVAL; + } + + if (ec->use_adaptive_tx_coalesce) { + rc->itr_setting |= ICE_ITR_DYNAMIC; + } else { + rc->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs); + rc->target_itr = ITR_TO_REG(rc->itr_setting); + } + break; + default: + dev_dbg(&pf->pdev->dev, "Invalid container type %d\n", c_type); + return -EINVAL; + } + + return 0; +} + +static int +__ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, + int q_num) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + int rx = -EINVAL, tx = -EINVAL; + struct ice_vsi *vsi = np->vsi; + + if (q_num < 0) { + int i; + + ice_for_each_q_vector(vsi, i) { + struct ice_q_vector *q_vector = vsi->q_vectors[i]; + + if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, + &q_vector->rx, vsi) || + ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, + &q_vector->tx, vsi)) + return -EINVAL; + } + + goto set_work_lmt; + } + + if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { + rx = ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, + &vsi->rx_rings[q_num]->q_vector->rx, + vsi); + tx = ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, + &vsi->tx_rings[q_num]->q_vector->tx, + vsi); + } else if (q_num < vsi->num_rxq) { + rx = ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, + &vsi->rx_rings[q_num]->q_vector->rx, + vsi); + } else if (q_num < vsi->num_txq) { + tx = ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, + &vsi->tx_rings[q_num]->q_vector->tx, + vsi); + } + + /* either q_num is invalid for both Rx and Tx queues or setting coalesce + * failed completely + */ + if (rx && tx) + return -EINVAL; + +set_work_lmt: + if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq) + vsi->work_lmt = max(ec->tx_max_coalesced_frames_irq, + ec->rx_max_coalesced_frames_irq); + + return 0; +} + +static int +ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) +{ + return __ice_set_coalesce(netdev, ec, -1); +} + +static int ice_set_per_q_coalesce(struct net_device *netdev, u32 q_num, + struct ethtool_coalesce *ec) +{ + return __ice_set_coalesce(netdev, ec, q_num); +} + static const struct ethtool_ops ice_ethtool_ops = { .get_link_ksettings = ice_get_link_ksettings, .set_link_ksettings = ice_set_link_ksettings, @@ -1834,6 +2086,8 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_link = ethtool_op_get_link, .get_eeprom_len = ice_get_eeprom_len, .get_eeprom = ice_get_eeprom, + .get_coalesce = ice_get_coalesce, + .set_coalesce = ice_set_coalesce, .get_strings = ice_get_strings, .set_phys_id = ice_set_phys_id, .get_ethtool_stats = ice_get_ethtool_stats, @@ -1850,6 +2104,8 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_rxfh_indir_size = ice_get_rxfh_indir_size, .get_rxfh = ice_get_rxfh, .set_rxfh = ice_set_rxfh, + .get_per_queue_coalesce = ice_get_per_q_coalesce, + .set_per_queue_coalesce = ice_set_per_q_coalesce, }; /** diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index aa646002d653..fc358ea81816 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -118,9 +118,11 @@ enum ice_rx_dtype { #define ICE_TX_ITR ICE_IDX_ITR1 #define ICE_ITR_8K 124 #define ICE_ITR_20K 50 +#define ICE_ITR_MAX 8160 #define ICE_DFLT_TX_ITR (ICE_ITR_20K | ICE_ITR_DYNAMIC) #define ICE_DFLT_RX_ITR (ICE_ITR_20K | ICE_ITR_DYNAMIC) #define ICE_ITR_DYNAMIC 0x8000 /* used as flag for itr_setting */ +#define ITR_IS_DYNAMIC(setting) (!!((setting) & ICE_ITR_DYNAMIC)) #define ITR_TO_REG(setting) ((setting) & ~ICE_ITR_DYNAMIC) #define ICE_ITR_GRAN_S 1 /* Assume ITR granularity is 2us */ #define ICE_ITR_MASK 0x1FFE /* ITR register value alignment mask */ -- cgit v1.2.3 From a8939784a17a54566e8d8ab26e9a9c36e4598281 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Wed, 19 Dec 2018 10:03:31 -0800 Subject: ice: Allow for software timestamping Use ethtool_op_get_ts_info to provide software timestamping. Signed-off-by: Tony Nguyen Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_ethtool.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 02316e32dfb3..1f6a5f073e91 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -2104,6 +2104,7 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_rxfh_indir_size = ice_get_rxfh_indir_size, .get_rxfh = ice_get_rxfh, .set_rxfh = ice_set_rxfh, + .get_ts_info = ethtool_op_get_ts_info, .get_per_queue_coalesce = ice_get_per_q_coalesce, .set_per_queue_coalesce = ice_set_per_q_coalesce, }; -- cgit v1.2.3 From cf909e19acf373a2e1d9bd877846a11bc8e20a54 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Dec 2018 10:03:32 -0800 Subject: ice: Offload SCTP checksum This patch adds the ability to offload SCTP checksum calculations to the NIC. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h | 1 + drivers/net/ethernet/intel/ice/ice_main.c | 1 + drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++++++ 4 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index ac8bf7491d08..55944e089558 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h index bb51dd7defb5..bd7c01db8c63 100644 --- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h +++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h @@ -346,6 +346,7 @@ enum ice_tx_desc_cmd_bits { ICE_TX_DESC_CMD_IIPT_IPV4 = 0x0040, /* 2 BITS */ ICE_TX_DESC_CMD_IIPT_IPV4_CSUM = 0x0060, /* 2 BITS */ ICE_TX_DESC_CMD_L4T_EOFT_TCP = 0x0100, /* 2 BITS */ + ICE_TX_DESC_CMD_L4T_EOFT_SCTP = 0x0200, /* 2 BITS */ ICE_TX_DESC_CMD_L4T_EOFT_UDP = 0x0300, /* 2 BITS */ }; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index e59f8b29af49..f4bf6bda32a9 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1528,6 +1528,7 @@ static int ice_cfg_netdev(struct ice_vsi *vsi) csumo_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | + NETIF_F_SCTP_CRC | NETIF_F_IPV6_CSUM; vlano_features = NETIF_F_HW_VLAN_CTAG_FILTER | diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 384ac5c82e00..2357fcac996b 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1465,6 +1465,12 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off) offset |= l4_len << ICE_TX_DESC_LEN_L4_LEN_S; break; case IPPROTO_SCTP: + /* enable SCTP checksum offload */ + cmd |= ICE_TX_DESC_CMD_L4T_EOFT_SCTP; + l4_len = sizeof(struct sctphdr) >> 2; + offset |= l4_len << ICE_TX_DESC_LEN_L4_LEN_S; + break; + default: if (first->tx_flags & ICE_TX_FLAGS_TSO) return -1; -- cgit v1.2.3 From aef74145f088478aa4ff3834395015b6a742c15a Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Dec 2018 10:03:33 -0800 Subject: ice: Add support for new PHY types This patch adds code for the detection and operation of several additional PHY types that support higher link speeds. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 39 +++- drivers/net/ethernet/intel/ice/ice_common.c | 124 ++++++++++- drivers/net/ethernet/intel/ice/ice_common.h | 3 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 262 +++++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h | 2 + drivers/net/ethernet/intel/ice/ice_sriov.c | 9 + drivers/net/ethernet/intel/ice/ice_type.h | 2 + 7 files changed, 418 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 526224ede3fa..242c78469181 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -847,7 +847,42 @@ struct ice_aqc_get_phy_caps { #define ICE_PHY_TYPE_LOW_40GBASE_KR4 BIT_ULL(33) #define ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC BIT_ULL(34) #define ICE_PHY_TYPE_LOW_40G_XLAUI BIT_ULL(35) +#define ICE_PHY_TYPE_LOW_50GBASE_CR2 BIT_ULL(36) +#define ICE_PHY_TYPE_LOW_50GBASE_SR2 BIT_ULL(37) +#define ICE_PHY_TYPE_LOW_50GBASE_LR2 BIT_ULL(38) +#define ICE_PHY_TYPE_LOW_50GBASE_KR2 BIT_ULL(39) +#define ICE_PHY_TYPE_LOW_50G_LAUI2_AOC_ACC BIT_ULL(40) +#define ICE_PHY_TYPE_LOW_50G_LAUI2 BIT_ULL(41) +#define ICE_PHY_TYPE_LOW_50G_AUI2_AOC_ACC BIT_ULL(42) +#define ICE_PHY_TYPE_LOW_50G_AUI2 BIT_ULL(43) +#define ICE_PHY_TYPE_LOW_50GBASE_CP BIT_ULL(44) +#define ICE_PHY_TYPE_LOW_50GBASE_SR BIT_ULL(45) +#define ICE_PHY_TYPE_LOW_50GBASE_FR BIT_ULL(46) +#define ICE_PHY_TYPE_LOW_50GBASE_LR BIT_ULL(47) +#define ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4 BIT_ULL(48) +#define ICE_PHY_TYPE_LOW_50G_AUI1_AOC_ACC BIT_ULL(49) +#define ICE_PHY_TYPE_LOW_50G_AUI1 BIT_ULL(50) +#define ICE_PHY_TYPE_LOW_100GBASE_CR4 BIT_ULL(51) +#define ICE_PHY_TYPE_LOW_100GBASE_SR4 BIT_ULL(52) +#define ICE_PHY_TYPE_LOW_100GBASE_LR4 BIT_ULL(53) +#define ICE_PHY_TYPE_LOW_100GBASE_KR4 BIT_ULL(54) +#define ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC BIT_ULL(55) +#define ICE_PHY_TYPE_LOW_100G_CAUI4 BIT_ULL(56) +#define ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC BIT_ULL(57) +#define ICE_PHY_TYPE_LOW_100G_AUI4 BIT_ULL(58) +#define ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4 BIT_ULL(59) +#define ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4 BIT_ULL(60) +#define ICE_PHY_TYPE_LOW_100GBASE_CP2 BIT_ULL(61) +#define ICE_PHY_TYPE_LOW_100GBASE_SR2 BIT_ULL(62) +#define ICE_PHY_TYPE_LOW_100GBASE_DR BIT_ULL(63) #define ICE_PHY_TYPE_LOW_MAX_INDEX 63 +/* The second set of defines is for phy_type_high. */ +#define ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4 BIT_ULL(0) +#define ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC BIT_ULL(1) +#define ICE_PHY_TYPE_HIGH_100G_CAUI2 BIT_ULL(2) +#define ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC BIT_ULL(3) +#define ICE_PHY_TYPE_HIGH_100G_AUI2 BIT_ULL(4) +#define ICE_PHY_TYPE_HIGH_MAX_INDEX 19 struct ice_aqc_get_phy_caps_data { __le64 phy_type_low; /* Use values from ICE_PHY_TYPE_LOW_* */ @@ -1025,10 +1060,12 @@ struct ice_aqc_get_link_status_data { #define ICE_AQ_LINK_SPEED_20GB BIT(6) #define ICE_AQ_LINK_SPEED_25GB BIT(7) #define ICE_AQ_LINK_SPEED_40GB BIT(8) +#define ICE_AQ_LINK_SPEED_50GB BIT(9) +#define ICE_AQ_LINK_SPEED_100GB BIT(10) #define ICE_AQ_LINK_SPEED_UNKNOWN BIT(15) __le32 reserved3; /* Aligns next field to 8-byte boundary */ __le64 phy_type_low; /* Use values from ICE_PHY_TYPE_LOW_* */ - __le64 reserved4; + __le64 phy_type_high; /* Use values from ICE_PHY_TYPE_HIGH_* */ }; /* Set event mask command (direct 0x0613) */ diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 19695749f903..ab308fc88920 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -165,8 +165,10 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode, cmd->param0 |= cpu_to_le16(report_mode); status = ice_aq_send_cmd(pi->hw, &desc, pcaps, pcaps_size, cd); - if (!status && report_mode == ICE_AQC_REPORT_TOPO_CAP) + if (!status && report_mode == ICE_AQC_REPORT_TOPO_CAP) { pi->phy.phy_type_low = le64_to_cpu(pcaps->phy_type_low); + pi->phy.phy_type_high = le64_to_cpu(pcaps->phy_type_high); + } return status; } @@ -183,6 +185,9 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi) return ICE_MEDIA_UNKNOWN; hw_link_info = &pi->phy.link_info; + if (hw_link_info->phy_type_low && hw_link_info->phy_type_high) + /* If more than one media type is selected, report unknown */ + return ICE_MEDIA_UNKNOWN; if (hw_link_info->phy_type_low) { switch (hw_link_info->phy_type_low) { @@ -196,6 +201,15 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi) case ICE_PHY_TYPE_LOW_25G_AUI_C2C: case ICE_PHY_TYPE_LOW_40GBASE_SR4: case ICE_PHY_TYPE_LOW_40GBASE_LR4: + case ICE_PHY_TYPE_LOW_50GBASE_SR2: + case ICE_PHY_TYPE_LOW_50GBASE_LR2: + case ICE_PHY_TYPE_LOW_50GBASE_SR: + case ICE_PHY_TYPE_LOW_50GBASE_FR: + case ICE_PHY_TYPE_LOW_50GBASE_LR: + case ICE_PHY_TYPE_LOW_100GBASE_SR4: + case ICE_PHY_TYPE_LOW_100GBASE_LR4: + case ICE_PHY_TYPE_LOW_100GBASE_SR2: + case ICE_PHY_TYPE_LOW_100GBASE_DR: return ICE_MEDIA_FIBER; case ICE_PHY_TYPE_LOW_100BASE_TX: case ICE_PHY_TYPE_LOW_1000BASE_T: @@ -209,6 +223,11 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi) case ICE_PHY_TYPE_LOW_25GBASE_CR_S: case ICE_PHY_TYPE_LOW_25GBASE_CR1: case ICE_PHY_TYPE_LOW_40GBASE_CR4: + case ICE_PHY_TYPE_LOW_50GBASE_CR2: + case ICE_PHY_TYPE_LOW_50GBASE_CP: + case ICE_PHY_TYPE_LOW_100GBASE_CR4: + case ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4: + case ICE_PHY_TYPE_LOW_100GBASE_CP2: return ICE_MEDIA_DA; case ICE_PHY_TYPE_LOW_1000BASE_KX: case ICE_PHY_TYPE_LOW_2500BASE_KX: @@ -219,10 +238,18 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi) case ICE_PHY_TYPE_LOW_25GBASE_KR1: case ICE_PHY_TYPE_LOW_25GBASE_KR_S: case ICE_PHY_TYPE_LOW_40GBASE_KR4: + case ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4: + case ICE_PHY_TYPE_LOW_50GBASE_KR2: + case ICE_PHY_TYPE_LOW_100GBASE_KR4: + case ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4: + return ICE_MEDIA_BACKPLANE; + } + } else { + switch (hw_link_info->phy_type_high) { + case ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4: return ICE_MEDIA_BACKPLANE; } } - return ICE_MEDIA_UNKNOWN; } @@ -274,6 +301,7 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse, /* update current link status information */ hw_link_info->link_speed = le16_to_cpu(link_data.link_speed); hw_link_info->phy_type_low = le64_to_cpu(link_data.phy_type_low); + hw_link_info->phy_type_high = le64_to_cpu(link_data.phy_type_high); *hw_media_type = ice_get_media_type(pi); hw_link_info->link_info = link_data.link_info; hw_link_info->an_info = link_data.an_info; @@ -1707,16 +1735,20 @@ void ice_clear_pxe_mode(struct ice_hw *hw) /** * ice_get_link_speed_based_on_phy_type - returns link speed * @phy_type_low: lower part of phy_type + * @phy_type_high: higher part of phy_type * - * This helper function will convert a phy_type_low to its corresponding link + * This helper function will convert an entry in phy type structure + * [phy_type_low, phy_type_high] to its corresponding link speed. + * Note: In the structure of [phy_type_low, phy_type_high], there should + * be one bit set, as this function will convert one phy type to its * speed. - * Note: In the structure of phy_type_low, there should be one bit set, as - * this function will convert one phy type to its speed. * If no bit gets set, ICE_LINK_SPEED_UNKNOWN will be returned * If more than one bit gets set, ICE_LINK_SPEED_UNKNOWN will be returned */ -static u16 ice_get_link_speed_based_on_phy_type(u64 phy_type_low) +static u16 +ice_get_link_speed_based_on_phy_type(u64 phy_type_low, u64 phy_type_high) { + u16 speed_phy_type_high = ICE_AQ_LINK_SPEED_UNKNOWN; u16 speed_phy_type_low = ICE_AQ_LINK_SPEED_UNKNOWN; switch (phy_type_low) { @@ -1770,41 +1802,110 @@ static u16 ice_get_link_speed_based_on_phy_type(u64 phy_type_low) case ICE_PHY_TYPE_LOW_40G_XLAUI: speed_phy_type_low = ICE_AQ_LINK_SPEED_40GB; break; + case ICE_PHY_TYPE_LOW_50GBASE_CR2: + case ICE_PHY_TYPE_LOW_50GBASE_SR2: + case ICE_PHY_TYPE_LOW_50GBASE_LR2: + case ICE_PHY_TYPE_LOW_50GBASE_KR2: + case ICE_PHY_TYPE_LOW_50G_LAUI2_AOC_ACC: + case ICE_PHY_TYPE_LOW_50G_LAUI2: + case ICE_PHY_TYPE_LOW_50G_AUI2_AOC_ACC: + case ICE_PHY_TYPE_LOW_50G_AUI2: + case ICE_PHY_TYPE_LOW_50GBASE_CP: + case ICE_PHY_TYPE_LOW_50GBASE_SR: + case ICE_PHY_TYPE_LOW_50GBASE_FR: + case ICE_PHY_TYPE_LOW_50GBASE_LR: + case ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4: + case ICE_PHY_TYPE_LOW_50G_AUI1_AOC_ACC: + case ICE_PHY_TYPE_LOW_50G_AUI1: + speed_phy_type_low = ICE_AQ_LINK_SPEED_50GB; + break; + case ICE_PHY_TYPE_LOW_100GBASE_CR4: + case ICE_PHY_TYPE_LOW_100GBASE_SR4: + case ICE_PHY_TYPE_LOW_100GBASE_LR4: + case ICE_PHY_TYPE_LOW_100GBASE_KR4: + case ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC: + case ICE_PHY_TYPE_LOW_100G_CAUI4: + case ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC: + case ICE_PHY_TYPE_LOW_100G_AUI4: + case ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4: + case ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4: + case ICE_PHY_TYPE_LOW_100GBASE_CP2: + case ICE_PHY_TYPE_LOW_100GBASE_SR2: + case ICE_PHY_TYPE_LOW_100GBASE_DR: + speed_phy_type_low = ICE_AQ_LINK_SPEED_100GB; + break; default: speed_phy_type_low = ICE_AQ_LINK_SPEED_UNKNOWN; break; } - return speed_phy_type_low; + switch (phy_type_high) { + case ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4: + case ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC: + case ICE_PHY_TYPE_HIGH_100G_CAUI2: + case ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC: + case ICE_PHY_TYPE_HIGH_100G_AUI2: + speed_phy_type_high = ICE_AQ_LINK_SPEED_100GB; + break; + default: + speed_phy_type_high = ICE_AQ_LINK_SPEED_UNKNOWN; + break; + } + + if (speed_phy_type_low == ICE_AQ_LINK_SPEED_UNKNOWN && + speed_phy_type_high == ICE_AQ_LINK_SPEED_UNKNOWN) + return ICE_AQ_LINK_SPEED_UNKNOWN; + else if (speed_phy_type_low != ICE_AQ_LINK_SPEED_UNKNOWN && + speed_phy_type_high != ICE_AQ_LINK_SPEED_UNKNOWN) + return ICE_AQ_LINK_SPEED_UNKNOWN; + else if (speed_phy_type_low != ICE_AQ_LINK_SPEED_UNKNOWN && + speed_phy_type_high == ICE_AQ_LINK_SPEED_UNKNOWN) + return speed_phy_type_low; + else + return speed_phy_type_high; } /** * ice_update_phy_type * @phy_type_low: pointer to the lower part of phy_type + * @phy_type_high: pointer to the higher part of phy_type * @link_speeds_bitmap: targeted link speeds bitmap * * Note: For the link_speeds_bitmap structure, you can check it at * [ice_aqc_get_link_status->link_speed]. Caller can pass in * link_speeds_bitmap include multiple speeds. * - * The value of phy_type_low will present a certain link speed. This helper - * function will turn on bits in the phy_type_low based on the value of + * Each entry in this [phy_type_low, phy_type_high] structure will + * present a certain link speed. This helper function will turn on bits + * in [phy_type_low, phy_type_high] structure based on the value of * link_speeds_bitmap input parameter. */ -void ice_update_phy_type(u64 *phy_type_low, u16 link_speeds_bitmap) +void +ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high, + u16 link_speeds_bitmap) { u16 speed = ICE_AQ_LINK_SPEED_UNKNOWN; + u64 pt_high; u64 pt_low; int index; /* We first check with low part of phy_type */ for (index = 0; index <= ICE_PHY_TYPE_LOW_MAX_INDEX; index++) { pt_low = BIT_ULL(index); - speed = ice_get_link_speed_based_on_phy_type(pt_low); + speed = ice_get_link_speed_based_on_phy_type(pt_low, 0); if (link_speeds_bitmap & speed) *phy_type_low |= BIT_ULL(index); } + + /* We then check with high part of phy_type */ + for (index = 0; index <= ICE_PHY_TYPE_HIGH_MAX_INDEX; index++) { + pt_high = BIT_ULL(index); + speed = ice_get_link_speed_based_on_phy_type(0, pt_high); + + if (link_speeds_bitmap & speed) + *phy_type_high |= BIT_ULL(index); + } } /** @@ -1936,6 +2037,7 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) if (ena_auto_link_update) cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; /* Copy over all the old settings */ + cfg.phy_type_high = pcaps->phy_type_high; cfg.phy_type_low = pcaps->phy_type_low; cfg.low_power_ctrl = pcaps->low_power_ctrl; cfg.eee_cap = pcaps->eee_cap; diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 81c1bb77a9fc..17e21874b75b 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -72,7 +72,8 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode, struct ice_aqc_get_phy_caps_data *caps, struct ice_sq_cd *cd); void -ice_update_phy_type(u64 *phy_type_low, u16 link_speeds_bitmap); +ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high, + u16 link_speeds_bitmap); enum ice_status ice_aq_manage_mac_write(struct ice_hw *hw, u8 *mac_addr, u8 flags, struct ice_sq_cd *cd); diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 1f6a5f073e91..a82f0202652d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -493,16 +493,20 @@ ice_get_ethtool_stats(struct net_device *netdev, * @netdev: network interface device structure * @ks: ethtool link ksettings struct to fill out */ -static void ice_phy_type_to_ethtool(struct net_device *netdev, - struct ethtool_link_ksettings *ks) +static void +ice_phy_type_to_ethtool(struct net_device *netdev, + struct ethtool_link_ksettings *ks) { struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_link_status *hw_link_info; + bool need_add_adv_mode = false; struct ice_vsi *vsi = np->vsi; + u64 phy_types_high; u64 phy_types_low; hw_link_info = &vsi->port_info->phy.link_info; phy_types_low = vsi->port_info->phy.phy_type_low; + phy_types_high = vsi->port_info->phy.phy_type_high; ethtool_link_ksettings_zero_link_mode(ks, supported); ethtool_link_ksettings_zero_link_mode(ks, advertising); @@ -651,6 +655,95 @@ static void ice_phy_type_to_ethtool(struct net_device *netdev, ethtool_link_ksettings_add_link_mode(ks, advertising, 40000baseLR4_Full); } + if (phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_CR2 || + phy_types_low & ICE_PHY_TYPE_LOW_50G_LAUI2_AOC_ACC || + phy_types_low & ICE_PHY_TYPE_LOW_50G_LAUI2 || + phy_types_low & ICE_PHY_TYPE_LOW_50G_AUI2_AOC_ACC || + phy_types_low & ICE_PHY_TYPE_LOW_50G_AUI2 || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_CP || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_SR || + phy_types_low & ICE_PHY_TYPE_LOW_50G_AUI1_AOC_ACC || + phy_types_low & ICE_PHY_TYPE_LOW_50G_AUI1) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 50000baseCR2_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 50000baseCR2_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_KR2 || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 50000baseKR2_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 50000baseKR2_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_SR2 || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_LR2 || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_FR || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_LR) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 50000baseSR2_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 50000baseSR2_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_CR4 || + phy_types_low & ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC || + phy_types_low & ICE_PHY_TYPE_LOW_100G_CAUI4 || + phy_types_low & ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC || + phy_types_low & ICE_PHY_TYPE_LOW_100G_AUI4 || + phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4 || + phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_CP2 || + phy_types_high & ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC || + phy_types_high & ICE_PHY_TYPE_HIGH_100G_CAUI2 || + phy_types_high & ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC || + phy_types_high & ICE_PHY_TYPE_HIGH_100G_AUI2) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseCR4_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB) + need_add_adv_mode = true; + } + if (need_add_adv_mode) { + need_add_adv_mode = false; + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100000baseCR4_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_SR4 || + phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_SR2) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseSR4_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB) + need_add_adv_mode = true; + } + if (need_add_adv_mode) { + need_add_adv_mode = false; + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100000baseSR4_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_LR4 || + phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_DR) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseLR4_ER4_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB) + need_add_adv_mode = true; + } + if (need_add_adv_mode) { + need_add_adv_mode = false; + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100000baseLR4_ER4_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_KR4 || + phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4 || + phy_types_high & ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseKR4_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB) + need_add_adv_mode = true; + } + if (need_add_adv_mode) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100000baseKR4_Full); /* Autoneg PHY types */ if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX || @@ -676,6 +769,24 @@ static void ice_phy_type_to_ethtool(struct net_device *netdev, ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); } + if (phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_CR2 || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_KR2 || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_CP || + phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4) { + ethtool_link_ksettings_add_link_mode(ks, supported, + Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + Autoneg); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_CR4 || + phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_KR4 || + phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4 || + phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_CP2) { + ethtool_link_ksettings_add_link_mode(ks, supported, + Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + Autoneg); + } } #define TEST_SET_BITS_TIMEOUT 50 @@ -687,13 +798,15 @@ static void ice_phy_type_to_ethtool(struct net_device *netdev, * @ks: ethtool ksettings to fill in * @netdev: network interface device structure */ -static void ice_get_settings_link_up(struct ethtool_link_ksettings *ks, - struct net_device *netdev) +static void +ice_get_settings_link_up(struct ethtool_link_ksettings *ks, + struct net_device *netdev) { struct ice_netdev_priv *np = netdev_priv(netdev); struct ethtool_link_ksettings cap_ksettings; struct ice_link_status *link_info; struct ice_vsi *vsi = np->vsi; + bool unrecog_phy_high = false; bool unrecog_phy_low = false; link_info = &vsi->port_info->phy.link_info; @@ -855,14 +968,116 @@ static void ice_get_settings_link_up(struct ethtool_link_ksettings *ks, ethtool_link_ksettings_add_link_mode(ks, advertising, 40000baseKR4_Full); break; + case ICE_PHY_TYPE_LOW_50GBASE_CR2: + case ICE_PHY_TYPE_LOW_50GBASE_CP: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 50000baseCR2_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 50000baseCR2_Full); + break; + case ICE_PHY_TYPE_LOW_50G_LAUI2_AOC_ACC: + case ICE_PHY_TYPE_LOW_50G_LAUI2: + case ICE_PHY_TYPE_LOW_50G_AUI2_AOC_ACC: + case ICE_PHY_TYPE_LOW_50G_AUI2: + case ICE_PHY_TYPE_LOW_50GBASE_SR: + case ICE_PHY_TYPE_LOW_50G_AUI1_AOC_ACC: + case ICE_PHY_TYPE_LOW_50G_AUI1: + ethtool_link_ksettings_add_link_mode(ks, supported, + 50000baseCR2_Full); + break; + case ICE_PHY_TYPE_LOW_50GBASE_KR2: + case ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 50000baseKR2_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 50000baseKR2_Full); + break; + case ICE_PHY_TYPE_LOW_50GBASE_SR2: + case ICE_PHY_TYPE_LOW_50GBASE_LR2: + case ICE_PHY_TYPE_LOW_50GBASE_FR: + case ICE_PHY_TYPE_LOW_50GBASE_LR: + ethtool_link_ksettings_add_link_mode(ks, supported, + 50000baseSR2_Full); + break; + case ICE_PHY_TYPE_LOW_100GBASE_CR4: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseCR4_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100000baseCR4_Full); + break; + case ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC: + case ICE_PHY_TYPE_LOW_100G_CAUI4: + case ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC: + case ICE_PHY_TYPE_LOW_100G_AUI4: + case ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4: + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseCR4_Full); + break; + case ICE_PHY_TYPE_LOW_100GBASE_CP2: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseCR4_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100000baseCR4_Full); + break; + case ICE_PHY_TYPE_LOW_100GBASE_SR4: + case ICE_PHY_TYPE_LOW_100GBASE_SR2: + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseSR4_Full); + break; + case ICE_PHY_TYPE_LOW_100GBASE_LR4: + case ICE_PHY_TYPE_LOW_100GBASE_DR: + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseLR4_ER4_Full); + break; + case ICE_PHY_TYPE_LOW_100GBASE_KR4: + case ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseKR4_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100000baseKR4_Full); + break; default: unrecog_phy_low = true; } - if (unrecog_phy_low) { + switch (link_info->phy_type_high) { + case ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseKR4_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100000baseKR4_Full); + break; + case ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC: + case ICE_PHY_TYPE_HIGH_100G_CAUI2: + case ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC: + case ICE_PHY_TYPE_HIGH_100G_AUI2: + ethtool_link_ksettings_add_link_mode(ks, supported, + 100000baseCR4_Full); + break; + default: + unrecog_phy_high = true; + } + + if (unrecog_phy_low && unrecog_phy_high) { /* if we got here and link is up something bad is afoot */ - netdev_info(netdev, "WARNING: Unrecognized PHY_Low (0x%llx).\n", + netdev_info(netdev, + "WARNING: Unrecognized PHY_Low (0x%llx).\n", (u64)link_info->phy_type_low); + netdev_info(netdev, + "WARNING: Unrecognized PHY_High (0x%llx).\n", + (u64)link_info->phy_type_high); } /* Now that we've worked out everything that could be supported by the @@ -874,6 +1089,12 @@ static void ice_get_settings_link_up(struct ethtool_link_ksettings *ks, ethtool_intersect_link_masks(ks, &cap_ksettings); switch (link_info->link_speed) { + case ICE_AQ_LINK_SPEED_100GB: + ks->base.speed = SPEED_100000; + break; + case ICE_AQ_LINK_SPEED_50GB: + ks->base.speed = SPEED_50000; + break; case ICE_AQ_LINK_SPEED_40GB: ks->base.speed = SPEED_40000; break; @@ -1067,6 +1288,23 @@ ice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks) ethtool_link_ksettings_test_link_mode(ks, advertising, 40000baseKR4_Full)) adv_link_speed |= ICE_AQ_LINK_SPEED_40GB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 50000baseCR2_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 50000baseKR2_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_50GB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 50000baseSR2_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_50GB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 100000baseCR4_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 100000baseSR4_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 100000baseLR4_ER4_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 100000baseKR4_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_100GB; return adv_link_speed; } @@ -1137,8 +1375,9 @@ ice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks, * * Set speed/duplex per media_types advertised/forced */ -static int ice_set_link_ksettings(struct net_device *netdev, - const struct ethtool_link_ksettings *ks) +static int +ice_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *ks) { u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT, lport = 0; struct ice_netdev_priv *np = netdev_priv(netdev); @@ -1150,6 +1389,7 @@ static int ice_set_link_ksettings(struct net_device *netdev, struct ice_port_info *p; u8 autoneg_changed = 0; enum ice_status status; + u64 phy_type_high; u64 phy_type_low; int err = 0; bool linkup; @@ -1265,7 +1505,7 @@ static int ice_set_link_ksettings(struct net_device *netdev, adv_link_speed = curr_link_speed; /* Convert the advertise link speeds to their corresponded PHY_TYPE */ - ice_update_phy_type(&phy_type_low, adv_link_speed); + ice_update_phy_type(&phy_type_low, &phy_type_high, adv_link_speed); if (!autoneg_changed && adv_link_speed == curr_link_speed) { netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); @@ -1284,7 +1524,9 @@ static int ice_set_link_ksettings(struct net_device *netdev, /* set link and auto negotiation so changes take effect */ config.caps |= ICE_AQ_PHY_ENA_LINK; - if (phy_type_low) { + if (phy_type_low || phy_type_high) { + config.phy_type_high = cpu_to_le64(phy_type_high) & + abilities->phy_type_high; config.phy_type_low = cpu_to_le64(phy_type_low) & abilities->phy_type_low; } else { diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h index bd7c01db8c63..ef4c79b5aa32 100644 --- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h +++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h @@ -489,5 +489,7 @@ static inline struct ice_rx_ptype_decoded ice_decode_rx_desc_ptype(u16 ptype) #define ICE_LINK_SPEED_20000MBPS 20000 #define ICE_LINK_SPEED_25000MBPS 25000 #define ICE_LINK_SPEED_40000MBPS 40000 +#define ICE_LINK_SPEED_50000MBPS 50000 +#define ICE_LINK_SPEED_100000MBPS 100000 #endif /* _ICE_LAN_TX_RX_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 533b989a23e1..d2db0d04e117 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -85,6 +85,12 @@ u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed) case ICE_AQ_LINK_SPEED_40GB: speed = ICE_LINK_SPEED_40000MBPS; break; + case ICE_AQ_LINK_SPEED_50GB: + speed = ICE_LINK_SPEED_50000MBPS; + break; + case ICE_AQ_LINK_SPEED_100GB: + speed = ICE_LINK_SPEED_100000MBPS; + break; default: speed = ICE_LINK_SPEED_UNKNOWN; break; @@ -116,6 +122,9 @@ u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed) break; case ICE_AQ_LINK_SPEED_40GB: /* fall through */ + case ICE_AQ_LINK_SPEED_50GB: + /* fall through */ + case ICE_AQ_LINK_SPEED_100GB: speed = (u32)VIRTCHNL_LINK_SPEED_40GB; break; default: diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index a078e2c98871..17086d5b5c33 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -90,6 +90,7 @@ enum ice_vsi_type { struct ice_link_status { /* Refer to ice_aq_phy_type for bits definition */ u64 phy_type_low; + u64 phy_type_high; u16 max_frame_size; u16 link_speed; u16 req_speeds; @@ -118,6 +119,7 @@ struct ice_phy_info { struct ice_link_status link_info; struct ice_link_status link_info_old; u64 phy_type_low; + u64 phy_type_high; enum ice_media_type media_type; u8 get_link_info; }; -- cgit v1.2.3 From d671e3e0dac9f637e2f49178923b7a0ac435e447 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 19 Dec 2018 10:03:34 -0800 Subject: ice: add const qualifier to mac_addr parameter The function ice_aq_manage_mac_write takes a pointer to a MAC address. The parameter is not marked const, even though the function doesn't need to modify it. This prevents passing a parameter that is already marked const. Update the function prototype to take a const pointer, to allow passing constant pointers to this function. Signed-off-by: Jacob Keller Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 6 +++--- drivers/net/ethernet/intel/ice/ice_common.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index ab308fc88920..b17ade424423 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1685,7 +1685,7 @@ enum ice_status ice_get_caps(struct ice_hw *hw) * This function is used to write MAC address to the NVM (0x0108). */ enum ice_status -ice_aq_manage_mac_write(struct ice_hw *hw, u8 *mac_addr, u8 flags, +ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags, struct ice_sq_cd *cd) { struct ice_aqc_manage_mac_write *cmd; @@ -1697,8 +1697,8 @@ ice_aq_manage_mac_write(struct ice_hw *hw, u8 *mac_addr, u8 flags, cmd->flags = flags; /* Prep values for flags, sah, sal */ - cmd->sah = htons(*((u16 *)mac_addr)); - cmd->sal = htonl(*((u32 *)(mac_addr + 2))); + cmd->sah = htons(*((const u16 *)mac_addr)); + cmd->sal = htonl(*((const u32 *)(mac_addr + 2))); return ice_aq_send_cmd(hw, &desc, NULL, 0, cd); } diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 17e21874b75b..d7c7c2ed8823 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -75,7 +75,7 @@ void ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high, u16 link_speeds_bitmap); enum ice_status -ice_aq_manage_mac_write(struct ice_hw *hw, u8 *mac_addr, u8 flags, +ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags, struct ice_sq_cd *cd); enum ice_status ice_clear_pf_cfg(struct ice_hw *hw); enum ice_status -- cgit v1.2.3 From 8a62ffe2753a845272f4f2100b5fca0b6053ff6f Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Fri, 21 Dec 2018 11:33:54 +0100 Subject: PM-runtime: Add new interface to get accounted time Some drivers (like i915/drm) needs to get the accounted suspended time. pm_runtime_suspended_time() will return the suspended accounted time in ns unit. Reviewed-by: Ulf Hansson Signed-off-by: Vincent Guittot Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 457be03b744d..a453090c9449 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -88,6 +88,21 @@ static void __update_runtime_status(struct device *dev, enum rpm_status status) dev->power.runtime_status = status; } +u64 pm_runtime_suspended_time(struct device *dev) +{ + unsigned long flags, time; + + spin_lock_irqsave(&dev->power.lock, flags); + + update_pm_runtime_accounting(dev); + time = dev->power.suspended_jiffies; + + spin_unlock_irqrestore(&dev->power.lock, flags); + + return jiffies_to_nsecs(time); +} +EXPORT_SYMBOL_GPL(pm_runtime_suspended_time); + /** * pm_runtime_deactivate_timer - Deactivate given device's suspend timer. * @dev: Device to handle. -- cgit v1.2.3 From 3b4ed2e2eb5583774a1ed4aa4596a5a3c55f2567 Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Fri, 21 Dec 2018 11:33:55 +0100 Subject: drm/i915: Move on the new pm runtime interface Use the new PM-runtime interface to get the accounted suspended time: pm_runtime_suspended_time(). This new interface helps to simplify and cleanup the code that computes __I915_SAMPLE_RC6_ESTIMATED and to remove direct access to internals of PM-runtime. Signed-off-by: Vincent Guittot Reviewed-by: Ulf Hansson Reviewed-by: Tvrtko Ursulin Signed-off-by: Rafael J. Wysocki --- drivers/gpu/drm/i915/i915_pmu.c | 16 ++++++---------- drivers/gpu/drm/i915/i915_pmu.h | 4 ++-- 2 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index d6c8f8fdfda5..3f76f605ac31 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -5,6 +5,7 @@ */ #include +#include #include "i915_pmu.h" #include "intel_ringbuffer.h" #include "i915_drv.h" @@ -478,7 +479,6 @@ static u64 get_rc6(struct drm_i915_private *i915) * counter value. */ spin_lock_irqsave(&i915->pmu.lock, flags); - spin_lock(&kdev->power.lock); /* * After the above branch intel_runtime_pm_get_if_in_use failed @@ -491,16 +491,13 @@ static u64 get_rc6(struct drm_i915_private *i915) * suspended and if not we cannot do better than report the last * known RC6 value. */ - if (kdev->power.runtime_status == RPM_SUSPENDED) { - if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) - i915->pmu.suspended_jiffies_last = - kdev->power.suspended_jiffies; + if (pm_runtime_status_suspended(kdev)) { + val = pm_runtime_suspended_time(kdev); - val = kdev->power.suspended_jiffies - - i915->pmu.suspended_jiffies_last; - val += jiffies - kdev->power.accounting_timestamp; + if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) + i915->pmu.suspended_time_last = val; - val = jiffies_to_nsecs(val); + val -= i915->pmu.suspended_time_last; val += i915->pmu.sample[__I915_SAMPLE_RC6].cur; i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val; @@ -510,7 +507,6 @@ static u64 get_rc6(struct drm_i915_private *i915) val = i915->pmu.sample[__I915_SAMPLE_RC6].cur; } - spin_unlock(&kdev->power.lock); spin_unlock_irqrestore(&i915->pmu.lock, flags); } diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h index 7f164ca3db12..3dc2a30188e7 100644 --- a/drivers/gpu/drm/i915/i915_pmu.h +++ b/drivers/gpu/drm/i915/i915_pmu.h @@ -95,9 +95,9 @@ struct i915_pmu { */ struct i915_pmu_sample sample[__I915_NUM_PMU_SAMPLERS]; /** - * @suspended_jiffies_last: Cached suspend time from PM core. + * @suspended_time_last: Cached suspend time from PM core. */ - unsigned long suspended_jiffies_last; + u64 suspended_time_last; /** * @i915_attr: Memory block holding device attributes. */ -- cgit v1.2.3 From 5b3a23a3cc94864aacc012532b36afa92a25b9c0 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 9 Jan 2019 06:56:49 +0100 Subject: i2c: imx: notify about real errors on dma i2c_imx_dma_request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least on i.MX5x, the DMA events for I2C and SDHC use the same channel and there can only be a single user. So in this case there should be no message emitted that looks like an error if the I2C device doesn't have an assigned DMA channel. In contrast real problems that were only emitted at debug level before should be described at a higher level to be better visible and so understandable. Signed-off-by: Oleksij Rempel Acked-by: Uwe Kleine-König Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index fa9ad53845d9..e28ef494dac8 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -285,9 +285,11 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, if (!dma) return; - dma->chan_tx = dma_request_slave_channel(dev, "tx"); - if (!dma->chan_tx) { - dev_dbg(dev, "can't request DMA tx channel\n"); + dma->chan_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(dma->chan_tx)) { + ret = PTR_ERR(dma->chan_rx); + if (ret != -ENODEV && ret != -EPROBE_DEFER) + dev_err(dev, "can't request DMA tx channel (%d)\n", ret); goto fail_al; } @@ -298,13 +300,15 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma_sconfig.direction = DMA_MEM_TO_DEV; ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig); if (ret < 0) { - dev_dbg(dev, "can't configure tx channel\n"); + dev_err(dev, "can't configure tx channel (%d)\n", ret); goto fail_tx; } - dma->chan_rx = dma_request_slave_channel(dev, "rx"); - if (!dma->chan_rx) { - dev_dbg(dev, "can't request DMA rx channel\n"); + dma->chan_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(dma->chan_rx)) { + ret = PTR_ERR(dma->chan_rx); + if (ret != -ENODEV && ret != -EPROBE_DEFER) + dev_err(dev, "can't request DMA rx channel (%d)\n", ret); goto fail_tx; } @@ -315,7 +319,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma_sconfig.direction = DMA_DEV_TO_MEM; ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig); if (ret < 0) { - dev_dbg(dev, "can't configure rx channel\n"); + dev_err(dev, "can't configure rx channel (%d)\n", ret); goto fail_rx; } @@ -332,7 +336,6 @@ fail_tx: dma_release_channel(dma->chan_tx); fail_al: devm_kfree(dev, dma); - dev_info(dev, "can't use DMA, using PIO instead.\n"); } static void i2c_imx_dma_callback(void *arg) -- cgit v1.2.3 From e1ab9a468e3b1636d60cebd0a778461270dde208 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 9 Jan 2019 06:56:50 +0100 Subject: i2c: imx: improve the error handling in i2c_imx_dma_request() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve the error handling in i2c_imx_dma_request() and let it return an error indication that the caller then can handle accordingly. Signed-off-by: Oleksij Rempel Acked-by: Uwe Kleine-König Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index e28ef494dac8..09b124547669 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -273,8 +273,8 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx, } /* Functions for DMA support */ -static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, - dma_addr_t phy_addr) +static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, + dma_addr_t phy_addr) { struct imx_i2c_dma *dma; struct dma_slave_config dma_sconfig; @@ -283,7 +283,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); if (!dma) - return; + return -ENOMEM; dma->chan_tx = dma_request_chan(dev, "tx"); if (IS_ERR(dma->chan_tx)) { @@ -328,7 +328,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n", dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); - return; + return 0; fail_rx: dma_release_channel(dma->chan_rx); @@ -336,6 +336,8 @@ fail_tx: dma_release_channel(dma->chan_tx); fail_al: devm_kfree(dev, dma); + /* return successfully if there is no dma support */ + return ret == -ENODEV ? 0 : ret; } static void i2c_imx_dma_callback(void *arg) @@ -1163,11 +1165,13 @@ static int i2c_imx_probe(struct platform_device *pdev) dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res); dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n", i2c_imx->adapter.name); - dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); /* Init DMA config if supported */ - i2c_imx_dma_request(i2c_imx, phy_addr); + ret = i2c_imx_dma_request(i2c_imx, phy_addr); + if (ret < 0) + goto clk_notifier_unregister; + dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); return 0; /* Return OK */ clk_notifier_unregister: -- cgit v1.2.3 From 21469df4676e89cb9fd4be489d9a2cc4af09db8c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 7 Jan 2019 12:28:54 +0530 Subject: cpufreq: Don't update new_policy on failures The local variable "new_policy" hasn't been used in the error path of cpufreq_online() since commit f9f41e3ef99a (cpufreq: Remove policy create/remove notifiers). Don't update it in that error path. Signed-off-by: Viresh Kumar [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e35a886e00bc..a8fa684f5f90 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1305,8 +1305,6 @@ static int cpufreq_online(unsigned int cpu) if (ret) { pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n", __func__, cpu, ret); - /* cpufreq_policy_free() will notify based on this */ - new_policy = false; goto out_destroy_policy; } -- cgit v1.2.3 From 4944514e6c7e613b578aaaafb2a2dd1a54bcf538 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 7 Jan 2019 11:33:43 -0600 Subject: cpufreq: e_powersaver: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/e_powersaver.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index 60bea302abbe..2d3ef208dd70 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -323,9 +323,8 @@ static int eps_cpu_init(struct cpufreq_policy *policy) states = 2; /* Allocate private data and frequency table for current cpu */ - centaur = kzalloc(sizeof(*centaur) - + (states + 1) * sizeof(struct cpufreq_frequency_table), - GFP_KERNEL); + centaur = kzalloc(struct_size(centaur, freq_table, states + 1), + GFP_KERNEL); if (!centaur) return -ENOMEM; eps_cpu[0] = centaur; -- cgit v1.2.3 From 3352976c892301fd576a2e9ff0ac7337b2e2ca48 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Fri, 11 Jan 2019 20:27:18 +0530 Subject: RDMA/iw_cxgb4: Fix the unchecked ep dereference The patch 944661dd97f4: "RDMA/iw_cxgb4: atomically lookup ep and get a reference" from May 6, 2016, leads to the following Smatch complaint: drivers/infiniband/hw/cxgb4/cm.c:2953 terminate() error: we previously assumed 'ep' could be null (see line 2945) Fixes: 944661dd97f4 ("RDMA/iw_cxgb4: atomically lookup ep and get a reference") Reported-by: Dan Carpenter Signed-off-by: Raju Rangoju Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/cxgb4/cm.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 8221813219e5..59917eb124da 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -2942,15 +2942,18 @@ static int terminate(struct c4iw_dev *dev, struct sk_buff *skb) ep = get_ep_from_tid(dev, tid); - if (ep && ep->com.qp) { - pr_warn("TERM received tid %u qpid %u\n", - tid, ep->com.qp->wq.sq.qid); - attrs.next_state = C4IW_QP_STATE_TERMINATE; - c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, - C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); + if (ep) { + if (ep->com.qp) { + pr_warn("TERM received tid %u qpid %u\n", tid, + ep->com.qp->wq.sq.qid); + attrs.next_state = C4IW_QP_STATE_TERMINATE; + c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, + C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); + } + + c4iw_put_ep(&ep->com); } else pr_warn("TERM received tid %u no ep/qp\n", tid); - c4iw_put_ep(&ep->com); return 0; } -- cgit v1.2.3 From 8e8aa1454205839030c9406febd1f6d4ece0d573 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 15 Jan 2019 00:00:48 -0600 Subject: RDMA/mlx5: Replace kzalloc with kcalloc Replace kzalloc() function with its 2-factor argument form, kcalloc(). This patch replaces cases of: kzalloc(a * b, gfp) with: kcalloc(a, b, gfp) This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Acked-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 4b1b56d54301..61064b7171fc 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3823,7 +3823,7 @@ mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev, if (fs_matcher->priority > MLX5_IB_FLOW_LAST_PRIO) return ERR_PTR(-ENOMEM); - dst = kzalloc(sizeof(*dst) * 2, GFP_KERNEL); + dst = kcalloc(2, sizeof(*dst), GFP_KERNEL); if (!dst) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From d80f8206905c1a8c3857d90f12bbfd6293b48a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 7 Jan 2019 20:53:52 +0100 Subject: pwm: imx: Split into two drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two PWM implementations called v1 (for i.MX1 and i.MX21) and v2 (for i.MX27 and later) have nothing in common apart from needing two clocks named "per" and "ipg" and being integrated in a SoC named i.MX. So split the file containing the two disjunct drivers into two files and two complete separate drivers. Signed-off-by: Uwe Kleine-König [thierry.reding@gmail.com: fix a modular build issue] Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 17 +- drivers/pwm/Makefile | 3 +- drivers/pwm/pwm-imx.c | 466 ------------------------------------------------ drivers/pwm/pwm-imx1.c | 199 +++++++++++++++++++++ drivers/pwm/pwm-imx27.c | 361 +++++++++++++++++++++++++++++++++++++ 5 files changed, 575 insertions(+), 471 deletions(-) delete mode 100644 drivers/pwm/pwm-imx.c create mode 100644 drivers/pwm/pwm-imx1.c create mode 100644 drivers/pwm/pwm-imx27.c (limited to 'drivers') diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index a8f47df0655a..54f8238aac0d 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -192,14 +192,23 @@ config PWM_IMG To compile this driver as a module, choose M here: the module will be called pwm-img -config PWM_IMX - tristate "i.MX PWM support" +config PWM_IMX1 + tristate "i.MX1 PWM support" depends on ARCH_MXC help - Generic PWM framework driver for i.MX. + Generic PWM framework driver for i.MX1 and i.MX21 To compile this driver as a module, choose M here: the module - will be called pwm-imx. + will be called pwm-imx1. + +config PWM_IMX27 + tristate "i.MX27 PWM support" + depends on ARCH_MXC + help + Generic PWM framework driver for i.MX27 and later i.MX SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-imx27. config PWM_JZ4740 tristate "Ingenic JZ47xx PWM support" diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 9c676a0dadf5..448825e892bc 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -17,7 +17,8 @@ obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o obj-$(CONFIG_PWM_IMG) += pwm-img.o -obj-$(CONFIG_PWM_IMX) += pwm-imx.o +obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o +obj-$(CONFIG_PWM_IMX27) += pwm-imx27.o obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o obj-$(CONFIG_PWM_LPC18XX_SCT) += pwm-lpc18xx-sct.o diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c deleted file mode 100644 index 30380fcb5cfb..000000000000 --- a/drivers/pwm/pwm-imx.c +++ /dev/null @@ -1,466 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * simple driver for PWM (Pulse Width Modulator) controller - * - * Derived from pxa PWM driver by eric miao - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* i.MX1 and i.MX21 share the same PWM function block: */ - -#define MX1_PWMC 0x00 /* PWM Control Register */ -#define MX1_PWMS 0x04 /* PWM Sample Register */ -#define MX1_PWMP 0x08 /* PWM Period Register */ - -#define MX1_PWMC_EN BIT(4) - -/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ - -#define MX3_PWMCR 0x00 /* PWM Control Register */ -#define MX3_PWMSR 0x04 /* PWM Status Register */ -#define MX3_PWMSAR 0x0C /* PWM Sample Register */ -#define MX3_PWMPR 0x10 /* PWM Period Register */ - -#define MX3_PWMCR_FWM GENMASK(27, 26) -#define MX3_PWMCR_STOPEN BIT(25) -#define MX3_PWMCR_DOZEN BIT(24) -#define MX3_PWMCR_WAITEN BIT(23) -#define MX3_PWMCR_DBGEN BIT(22) -#define MX3_PWMCR_BCTR BIT(21) -#define MX3_PWMCR_HCTR BIT(20) - -#define MX3_PWMCR_POUTC GENMASK(19, 18) -#define MX3_PWMCR_POUTC_NORMAL 0 -#define MX3_PWMCR_POUTC_INVERTED 1 -#define MX3_PWMCR_POUTC_OFF 2 - -#define MX3_PWMCR_CLKSRC GENMASK(17, 16) -#define MX3_PWMCR_CLKSRC_OFF 0 -#define MX3_PWMCR_CLKSRC_IPG 1 -#define MX3_PWMCR_CLKSRC_IPG_HIGH 2 -#define MX3_PWMCR_CLKSRC_IPG_32K 3 - -#define MX3_PWMCR_PRESCALER GENMASK(15, 4) - -#define MX3_PWMCR_SWR BIT(3) - -#define MX3_PWMCR_REPEAT GENMASK(2, 1) -#define MX3_PWMCR_REPEAT_1X 0 -#define MX3_PWMCR_REPEAT_2X 1 -#define MX3_PWMCR_REPEAT_4X 2 -#define MX3_PWMCR_REPEAT_8X 3 - -#define MX3_PWMCR_EN BIT(0) - -#define MX3_PWMSR_FWE BIT(6) -#define MX3_PWMSR_CMP BIT(5) -#define MX3_PWMSR_ROV BIT(4) -#define MX3_PWMSR_FE BIT(3) - -#define MX3_PWMSR_FIFOAV GENMASK(2, 0) -#define MX3_PWMSR_FIFOAV_EMPTY 0 -#define MX3_PWMSR_FIFOAV_1WORD 1 -#define MX3_PWMSR_FIFOAV_2WORDS 2 -#define MX3_PWMSR_FIFOAV_3WORDS 3 -#define MX3_PWMSR_FIFOAV_4WORDS 4 - -#define MX3_PWMCR_PRESCALER_SET(x) FIELD_PREP(MX3_PWMCR_PRESCALER, (x) - 1) -#define MX3_PWMCR_PRESCALER_GET(x) (FIELD_GET(MX3_PWMCR_PRESCALER, \ - (x)) + 1) - -#define MX3_PWM_SWR_LOOP 5 - -/* PWMPR register value of 0xffff has the same effect as 0xfffe */ -#define MX3_PWMPR_MAX 0xfffe - -struct imx_chip { - struct clk *clk_ipg; - - struct clk *clk_per; - - void __iomem *mmio_base; - - struct pwm_chip chip; -}; - -#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) - -static int imx_pwm_clk_prepare_enable(struct pwm_chip *chip) -{ - struct imx_chip *imx = to_imx_chip(chip); - int ret; - - ret = clk_prepare_enable(imx->clk_ipg); - if (ret) - return ret; - - ret = clk_prepare_enable(imx->clk_per); - if (ret) { - clk_disable_unprepare(imx->clk_ipg); - return ret; - } - - return 0; -} - -static void imx_pwm_clk_disable_unprepare(struct pwm_chip *chip) -{ - struct imx_chip *imx = to_imx_chip(chip); - - clk_disable_unprepare(imx->clk_per); - clk_disable_unprepare(imx->clk_ipg); -} - -static void imx_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, struct pwm_state *state) -{ - struct imx_chip *imx = to_imx_chip(chip); - u32 period, prescaler, pwm_clk, ret, val; - u64 tmp; - - ret = imx_pwm_clk_prepare_enable(chip); - if (ret < 0) - return; - - val = readl(imx->mmio_base + MX3_PWMCR); - - if (val & MX3_PWMCR_EN) { - state->enabled = true; - ret = imx_pwm_clk_prepare_enable(chip); - if (ret) - return; - } else { - state->enabled = false; - } - - switch (FIELD_GET(MX3_PWMCR_POUTC, val)) { - case MX3_PWMCR_POUTC_NORMAL: - state->polarity = PWM_POLARITY_NORMAL; - break; - case MX3_PWMCR_POUTC_INVERTED: - state->polarity = PWM_POLARITY_INVERSED; - break; - default: - dev_warn(chip->dev, "can't set polarity, output disconnected"); - } - - prescaler = MX3_PWMCR_PRESCALER_GET(val); - pwm_clk = clk_get_rate(imx->clk_per); - pwm_clk = DIV_ROUND_CLOSEST_ULL(pwm_clk, prescaler); - val = readl(imx->mmio_base + MX3_PWMPR); - period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val; - - /* PWMOUT (Hz) = PWMCLK / (PWMPR + 2) */ - tmp = NSEC_PER_SEC * (u64)(period + 2); - state->period = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); - - /* PWMSAR can be read only if PWM is enabled */ - if (state->enabled) { - val = readl(imx->mmio_base + MX3_PWMSAR); - tmp = NSEC_PER_SEC * (u64)(val); - state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); - } else { - state->duty_cycle = 0; - } - - imx_pwm_clk_disable_unprepare(chip); -} - -static int imx_pwm_config_v1(struct pwm_chip *chip, - struct pwm_device *pwm, int duty_ns, int period_ns) -{ - struct imx_chip *imx = to_imx_chip(chip); - - /* - * The PWM subsystem allows for exact frequencies. However, - * I cannot connect a scope on my device to the PWM line and - * thus cannot provide the program the PWM controller - * exactly. Instead, I'm relying on the fact that the - * Bootloader (u-boot or WinCE+haret) has programmed the PWM - * function group already. So I'll just modify the PWM sample - * register to follow the ratio of duty_ns vs. period_ns - * accordingly. - * - * This is good enough for programming the brightness of - * the LCD backlight. - * - * The real implementation would divide PERCLK[0] first by - * both the prescaler (/1 .. /128) and then by CLKSEL - * (/2 .. /16). - */ - u32 max = readl(imx->mmio_base + MX1_PWMP); - u32 p = max * duty_ns / period_ns; - writel(max - p, imx->mmio_base + MX1_PWMS); - - return 0; -} - -static int imx_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct imx_chip *imx = to_imx_chip(chip); - u32 val; - int ret; - - ret = imx_pwm_clk_prepare_enable(chip); - if (ret < 0) - return ret; - - val = readl(imx->mmio_base + MX1_PWMC); - val |= MX1_PWMC_EN; - writel(val, imx->mmio_base + MX1_PWMC); - - return 0; -} - -static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct imx_chip *imx = to_imx_chip(chip); - u32 val; - - val = readl(imx->mmio_base + MX1_PWMC); - val &= ~MX1_PWMC_EN; - writel(val, imx->mmio_base + MX1_PWMC); - - imx_pwm_clk_disable_unprepare(chip); -} - -static void imx_pwm_sw_reset(struct pwm_chip *chip) -{ - struct imx_chip *imx = to_imx_chip(chip); - struct device *dev = chip->dev; - int wait_count = 0; - u32 cr; - - writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); - do { - usleep_range(200, 1000); - cr = readl(imx->mmio_base + MX3_PWMCR); - } while ((cr & MX3_PWMCR_SWR) && - (wait_count++ < MX3_PWM_SWR_LOOP)); - - if (cr & MX3_PWMCR_SWR) - dev_warn(dev, "software reset timeout\n"); -} - -static void imx_pwm_wait_fifo_slot(struct pwm_chip *chip, - struct pwm_device *pwm) -{ - struct imx_chip *imx = to_imx_chip(chip); - struct device *dev = chip->dev; - unsigned int period_ms; - int fifoav; - u32 sr; - - sr = readl(imx->mmio_base + MX3_PWMSR); - fifoav = FIELD_GET(MX3_PWMSR_FIFOAV, sr); - if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { - period_ms = DIV_ROUND_UP(pwm_get_period(pwm), - NSEC_PER_MSEC); - msleep(period_ms); - - sr = readl(imx->mmio_base + MX3_PWMSR); - if (fifoav == FIELD_GET(MX3_PWMSR_FIFOAV, sr)) - dev_warn(dev, "there is no free FIFO slot\n"); - } -} - -static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) -{ - unsigned long period_cycles, duty_cycles, prescale; - struct imx_chip *imx = to_imx_chip(chip); - struct pwm_state cstate; - unsigned long long c; - int ret; - u32 cr; - - pwm_get_state(pwm, &cstate); - - if (state->enabled) { - c = clk_get_rate(imx->clk_per); - c *= state->period; - - do_div(c, 1000000000); - period_cycles = c; - - prescale = period_cycles / 0x10000 + 1; - - period_cycles /= prescale; - c = (unsigned long long)period_cycles * state->duty_cycle; - do_div(c, state->period); - duty_cycles = c; - - /* - * according to imx pwm RM, the real period value should be - * PERIOD value in PWMPR plus 2. - */ - if (period_cycles > 2) - period_cycles -= 2; - else - period_cycles = 0; - - /* - * Wait for a free FIFO slot if the PWM is already enabled, and - * flush the FIFO if the PWM was disabled and is about to be - * enabled. - */ - if (cstate.enabled) { - imx_pwm_wait_fifo_slot(chip, pwm); - } else { - ret = imx_pwm_clk_prepare_enable(chip); - if (ret) - return ret; - - imx_pwm_sw_reset(chip); - } - - writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); - writel(period_cycles, imx->mmio_base + MX3_PWMPR); - - cr = MX3_PWMCR_PRESCALER_SET(prescale) | - MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN | - FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) | - MX3_PWMCR_DBGEN | MX3_PWMCR_EN; - - if (state->polarity == PWM_POLARITY_INVERSED) - cr |= FIELD_PREP(MX3_PWMCR_POUTC, - MX3_PWMCR_POUTC_INVERTED); - - writel(cr, imx->mmio_base + MX3_PWMCR); - } else if (cstate.enabled) { - writel(0, imx->mmio_base + MX3_PWMCR); - - imx_pwm_clk_disable_unprepare(chip); - } - - return 0; -} - -static const struct pwm_ops imx_pwm_ops_v1 = { - .enable = imx_pwm_enable_v1, - .disable = imx_pwm_disable_v1, - .config = imx_pwm_config_v1, - .owner = THIS_MODULE, -}; - -static const struct pwm_ops imx_pwm_ops_v2 = { - .apply = imx_pwm_apply_v2, - .get_state = imx_pwm_get_state, - .owner = THIS_MODULE, -}; - -struct imx_pwm_data { - bool polarity_supported; - const struct pwm_ops *ops; -}; - -static struct imx_pwm_data imx_pwm_data_v1 = { - .ops = &imx_pwm_ops_v1, -}; - -static struct imx_pwm_data imx_pwm_data_v2 = { - .polarity_supported = true, - .ops = &imx_pwm_ops_v2, -}; - -static const struct of_device_id imx_pwm_dt_ids[] = { - { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, }, - { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids); - -static int imx_pwm_probe(struct platform_device *pdev) -{ - const struct of_device_id *of_id = - of_match_device(imx_pwm_dt_ids, &pdev->dev); - const struct imx_pwm_data *data; - struct imx_chip *imx; - struct resource *r; - - if (!of_id) - return -ENODEV; - - data = of_id->data; - - imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); - if (imx == NULL) - return -ENOMEM; - - platform_set_drvdata(pdev, imx); - - imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(imx->clk_ipg)) { - dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", - PTR_ERR(imx->clk_ipg)); - return PTR_ERR(imx->clk_ipg); - } - - imx->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(imx->clk_per)) { - int ret = PTR_ERR(imx->clk_per); - - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "failed to get peripheral clock: %d\n", - ret); - - return ret; - } - - imx->chip.ops = data->ops; - imx->chip.dev = &pdev->dev; - imx->chip.base = -1; - imx->chip.npwm = 1; - - if (data->polarity_supported) { - dev_dbg(&pdev->dev, "PWM supports output inversion\n"); - imx->chip.of_xlate = of_pwm_xlate_with_flags; - imx->chip.of_pwm_n_cells = 3; - } - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); - if (IS_ERR(imx->mmio_base)) - return PTR_ERR(imx->mmio_base); - - return pwmchip_add(&imx->chip); -} - -static int imx_pwm_remove(struct platform_device *pdev) -{ - struct imx_chip *imx; - - imx = platform_get_drvdata(pdev); - - imx_pwm_clk_disable_unprepare(&imx->chip); - - return pwmchip_remove(&imx->chip); -} - -static struct platform_driver imx_pwm_driver = { - .driver = { - .name = "imx-pwm", - .of_match_table = imx_pwm_dt_ids, - }, - .probe = imx_pwm_probe, - .remove = imx_pwm_remove, -}; - -module_platform_driver(imx_pwm_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Sascha Hauer "); diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c new file mode 100644 index 000000000000..f8b2c2e001a7 --- /dev/null +++ b/drivers/pwm/pwm-imx1.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * simple driver for PWM (Pulse Width Modulator) controller + * + * Derived from pxa PWM driver by eric miao + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MX1_PWMC 0x00 /* PWM Control Register */ +#define MX1_PWMS 0x04 /* PWM Sample Register */ +#define MX1_PWMP 0x08 /* PWM Period Register */ + +#define MX1_PWMC_EN BIT(4) + +struct pwm_imx1_chip { + struct clk *clk_ipg; + struct clk *clk_per; + void __iomem *mmio_base; + struct pwm_chip chip; +}; + +#define to_pwm_imx1_chip(chip) container_of(chip, struct pwm_imx1_chip, chip) + +static int pwm_imx1_clk_prepare_enable(struct pwm_chip *chip) +{ + struct pwm_imx1_chip *imx = to_pwm_imx1_chip(chip); + int ret; + + ret = clk_prepare_enable(imx->clk_ipg); + if (ret) + return ret; + + ret = clk_prepare_enable(imx->clk_per); + if (ret) { + clk_disable_unprepare(imx->clk_ipg); + return ret; + } + + return 0; +} + +static void pwm_imx1_clk_disable_unprepare(struct pwm_chip *chip) +{ + struct pwm_imx1_chip *imx = to_pwm_imx1_chip(chip); + + clk_disable_unprepare(imx->clk_per); + clk_disable_unprepare(imx->clk_ipg); +} + +static int pwm_imx1_config(struct pwm_chip *chip, + struct pwm_device *pwm, int duty_ns, int period_ns) +{ + struct pwm_imx1_chip *imx = to_pwm_imx1_chip(chip); + u32 max, p; + + /* + * The PWM subsystem allows for exact frequencies. However, + * I cannot connect a scope on my device to the PWM line and + * thus cannot provide the program the PWM controller + * exactly. Instead, I'm relying on the fact that the + * Bootloader (u-boot or WinCE+haret) has programmed the PWM + * function group already. So I'll just modify the PWM sample + * register to follow the ratio of duty_ns vs. period_ns + * accordingly. + * + * This is good enough for programming the brightness of + * the LCD backlight. + * + * The real implementation would divide PERCLK[0] first by + * both the prescaler (/1 .. /128) and then by CLKSEL + * (/2 .. /16). + */ + max = readl(imx->mmio_base + MX1_PWMP); + p = max * duty_ns / period_ns; + + writel(max - p, imx->mmio_base + MX1_PWMS); + + return 0; +} + +static int pwm_imx1_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct pwm_imx1_chip *imx = to_pwm_imx1_chip(chip); + u32 value; + int ret; + + ret = pwm_imx1_clk_prepare_enable(chip); + if (ret < 0) + return ret; + + value = readl(imx->mmio_base + MX1_PWMC); + value |= MX1_PWMC_EN; + writel(value, imx->mmio_base + MX1_PWMC); + + return 0; +} + +static void pwm_imx1_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct pwm_imx1_chip *imx = to_pwm_imx1_chip(chip); + u32 value; + + value = readl(imx->mmio_base + MX1_PWMC); + value &= ~MX1_PWMC_EN; + writel(value, imx->mmio_base + MX1_PWMC); + + pwm_imx1_clk_disable_unprepare(chip); +} + +static const struct pwm_ops pwm_imx1_ops = { + .enable = pwm_imx1_enable, + .disable = pwm_imx1_disable, + .config = pwm_imx1_config, + .owner = THIS_MODULE, +}; + +static const struct of_device_id pwm_imx1_dt_ids[] = { + { .compatible = "fsl,imx1-pwm", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pwm_imx1_dt_ids); + +static int pwm_imx1_probe(struct platform_device *pdev) +{ + struct pwm_imx1_chip *imx; + struct resource *r; + + imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); + if (!imx) + return -ENOMEM; + + platform_set_drvdata(pdev, imx); + + imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(imx->clk_ipg)) { + dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", + PTR_ERR(imx->clk_ipg)); + return PTR_ERR(imx->clk_ipg); + } + + imx->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(imx->clk_per)) { + int ret = PTR_ERR(imx->clk_per); + + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "failed to get peripheral clock: %d\n", + ret); + + return ret; + } + + imx->chip.ops = &pwm_imx1_ops; + imx->chip.dev = &pdev->dev; + imx->chip.base = -1; + imx->chip.npwm = 1; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(imx->mmio_base)) + return PTR_ERR(imx->mmio_base); + + return pwmchip_add(&imx->chip); +} + +static int pwm_imx1_remove(struct platform_device *pdev) +{ + struct pwm_imx1_chip *imx = platform_get_drvdata(pdev); + + pwm_imx1_clk_disable_unprepare(&imx->chip); + + return pwmchip_remove(&imx->chip); +} + +static struct platform_driver pwm_imx1_driver = { + .driver = { + .name = "pwm-imx1", + .of_match_table = pwm_imx1_dt_ids, + }, + .probe = pwm_imx1_probe, + .remove = pwm_imx1_remove, +}; +module_platform_driver(pwm_imx1_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Sascha Hauer "); diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c new file mode 100644 index 000000000000..8b8b1c6b7f29 --- /dev/null +++ b/drivers/pwm/pwm-imx27.c @@ -0,0 +1,361 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * simple driver for PWM (Pulse Width Modulator) controller + * + * Derived from pxa PWM driver by eric miao + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MX3_PWMCR 0x00 /* PWM Control Register */ +#define MX3_PWMSR 0x04 /* PWM Status Register */ +#define MX3_PWMSAR 0x0C /* PWM Sample Register */ +#define MX3_PWMPR 0x10 /* PWM Period Register */ + +#define MX3_PWMCR_FWM GENMASK(27, 26) +#define MX3_PWMCR_STOPEN BIT(25) +#define MX3_PWMCR_DOZEN BIT(24) +#define MX3_PWMCR_WAITEN BIT(23) +#define MX3_PWMCR_DBGEN BIT(22) +#define MX3_PWMCR_BCTR BIT(21) +#define MX3_PWMCR_HCTR BIT(20) + +#define MX3_PWMCR_POUTC GENMASK(19, 18) +#define MX3_PWMCR_POUTC_NORMAL 0 +#define MX3_PWMCR_POUTC_INVERTED 1 +#define MX3_PWMCR_POUTC_OFF 2 + +#define MX3_PWMCR_CLKSRC GENMASK(17, 16) +#define MX3_PWMCR_CLKSRC_OFF 0 +#define MX3_PWMCR_CLKSRC_IPG 1 +#define MX3_PWMCR_CLKSRC_IPG_HIGH 2 +#define MX3_PWMCR_CLKSRC_IPG_32K 3 + +#define MX3_PWMCR_PRESCALER GENMASK(15, 4) + +#define MX3_PWMCR_SWR BIT(3) + +#define MX3_PWMCR_REPEAT GENMASK(2, 1) +#define MX3_PWMCR_REPEAT_1X 0 +#define MX3_PWMCR_REPEAT_2X 1 +#define MX3_PWMCR_REPEAT_4X 2 +#define MX3_PWMCR_REPEAT_8X 3 + +#define MX3_PWMCR_EN BIT(0) + +#define MX3_PWMSR_FWE BIT(6) +#define MX3_PWMSR_CMP BIT(5) +#define MX3_PWMSR_ROV BIT(4) +#define MX3_PWMSR_FE BIT(3) + +#define MX3_PWMSR_FIFOAV GENMASK(2, 0) +#define MX3_PWMSR_FIFOAV_EMPTY 0 +#define MX3_PWMSR_FIFOAV_1WORD 1 +#define MX3_PWMSR_FIFOAV_2WORDS 2 +#define MX3_PWMSR_FIFOAV_3WORDS 3 +#define MX3_PWMSR_FIFOAV_4WORDS 4 + +#define MX3_PWMCR_PRESCALER_SET(x) FIELD_PREP(MX3_PWMCR_PRESCALER, (x) - 1) +#define MX3_PWMCR_PRESCALER_GET(x) (FIELD_GET(MX3_PWMCR_PRESCALER, \ + (x)) + 1) + +#define MX3_PWM_SWR_LOOP 5 + +/* PWMPR register value of 0xffff has the same effect as 0xfffe */ +#define MX3_PWMPR_MAX 0xfffe + +struct pwm_imx27_chip { + struct clk *clk_ipg; + struct clk *clk_per; + void __iomem *mmio_base; + struct pwm_chip chip; +}; + +#define to_pwm_imx27_chip(chip) container_of(chip, struct pwm_imx27_chip, chip) + +static int pwm_imx27_clk_prepare_enable(struct pwm_chip *chip) +{ + struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); + int ret; + + ret = clk_prepare_enable(imx->clk_ipg); + if (ret) + return ret; + + ret = clk_prepare_enable(imx->clk_per); + if (ret) { + clk_disable_unprepare(imx->clk_ipg); + return ret; + } + + return 0; +} + +static void pwm_imx27_clk_disable_unprepare(struct pwm_chip *chip) +{ + struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); + + clk_disable_unprepare(imx->clk_per); + clk_disable_unprepare(imx->clk_ipg); +} + +static void pwm_imx27_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, struct pwm_state *state) +{ + struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); + u32 period, prescaler, pwm_clk, ret, val; + u64 tmp; + + ret = pwm_imx27_clk_prepare_enable(chip); + if (ret < 0) + return; + + val = readl(imx->mmio_base + MX3_PWMCR); + + if (val & MX3_PWMCR_EN) { + state->enabled = true; + ret = pwm_imx27_clk_prepare_enable(chip); + if (ret) + return; + } else { + state->enabled = false; + } + + switch (FIELD_GET(MX3_PWMCR_POUTC, val)) { + case MX3_PWMCR_POUTC_NORMAL: + state->polarity = PWM_POLARITY_NORMAL; + break; + case MX3_PWMCR_POUTC_INVERTED: + state->polarity = PWM_POLARITY_INVERSED; + break; + default: + dev_warn(chip->dev, "can't set polarity, output disconnected"); + } + + prescaler = MX3_PWMCR_PRESCALER_GET(val); + pwm_clk = clk_get_rate(imx->clk_per); + pwm_clk = DIV_ROUND_CLOSEST_ULL(pwm_clk, prescaler); + val = readl(imx->mmio_base + MX3_PWMPR); + period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val; + + /* PWMOUT (Hz) = PWMCLK / (PWMPR + 2) */ + tmp = NSEC_PER_SEC * (u64)(period + 2); + state->period = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); + + /* PWMSAR can be read only if PWM is enabled */ + if (state->enabled) { + val = readl(imx->mmio_base + MX3_PWMSAR); + tmp = NSEC_PER_SEC * (u64)(val); + state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); + } else { + state->duty_cycle = 0; + } + + pwm_imx27_clk_disable_unprepare(chip); +} + +static void pwm_imx27_sw_reset(struct pwm_chip *chip) +{ + struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); + struct device *dev = chip->dev; + int wait_count = 0; + u32 cr; + + writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); + do { + usleep_range(200, 1000); + cr = readl(imx->mmio_base + MX3_PWMCR); + } while ((cr & MX3_PWMCR_SWR) && + (wait_count++ < MX3_PWM_SWR_LOOP)); + + if (cr & MX3_PWMCR_SWR) + dev_warn(dev, "software reset timeout\n"); +} + +static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip, + struct pwm_device *pwm) +{ + struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); + struct device *dev = chip->dev; + unsigned int period_ms; + int fifoav; + u32 sr; + + sr = readl(imx->mmio_base + MX3_PWMSR); + fifoav = FIELD_GET(MX3_PWMSR_FIFOAV, sr); + if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { + period_ms = DIV_ROUND_UP(pwm_get_period(pwm), + NSEC_PER_MSEC); + msleep(period_ms); + + sr = readl(imx->mmio_base + MX3_PWMSR); + if (fifoav == FIELD_GET(MX3_PWMSR_FIFOAV, sr)) + dev_warn(dev, "there is no free FIFO slot\n"); + } +} + +static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + unsigned long period_cycles, duty_cycles, prescale; + struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); + struct pwm_state cstate; + unsigned long long c; + int ret; + u32 cr; + + pwm_get_state(pwm, &cstate); + + if (state->enabled) { + c = clk_get_rate(imx->clk_per); + c *= state->period; + + do_div(c, 1000000000); + period_cycles = c; + + prescale = period_cycles / 0x10000 + 1; + + period_cycles /= prescale; + c = (unsigned long long)period_cycles * state->duty_cycle; + do_div(c, state->period); + duty_cycles = c; + + /* + * according to imx pwm RM, the real period value should be + * PERIOD value in PWMPR plus 2. + */ + if (period_cycles > 2) + period_cycles -= 2; + else + period_cycles = 0; + + /* + * Wait for a free FIFO slot if the PWM is already enabled, and + * flush the FIFO if the PWM was disabled and is about to be + * enabled. + */ + if (cstate.enabled) { + pwm_imx27_wait_fifo_slot(chip, pwm); + } else { + ret = pwm_imx27_clk_prepare_enable(chip); + if (ret) + return ret; + + pwm_imx27_sw_reset(chip); + } + + writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); + writel(period_cycles, imx->mmio_base + MX3_PWMPR); + + cr = MX3_PWMCR_PRESCALER_SET(prescale) | + MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN | + FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) | + MX3_PWMCR_DBGEN | MX3_PWMCR_EN; + + if (state->polarity == PWM_POLARITY_INVERSED) + cr |= FIELD_PREP(MX3_PWMCR_POUTC, + MX3_PWMCR_POUTC_INVERTED); + + writel(cr, imx->mmio_base + MX3_PWMCR); + } else if (cstate.enabled) { + writel(0, imx->mmio_base + MX3_PWMCR); + + pwm_imx27_clk_disable_unprepare(chip); + } + + return 0; +} + +static const struct pwm_ops pwm_imx27_ops = { + .apply = pwm_imx27_apply, + .get_state = pwm_imx27_get_state, + .owner = THIS_MODULE, +}; + +static const struct of_device_id pwm_imx27_dt_ids[] = { + { .compatible = "fsl,imx27-pwm", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids); + +static int pwm_imx27_probe(struct platform_device *pdev) +{ + struct pwm_imx27_chip *imx; + struct resource *r; + + imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); + if (imx == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, imx); + + imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(imx->clk_ipg)) { + dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", + PTR_ERR(imx->clk_ipg)); + return PTR_ERR(imx->clk_ipg); + } + + imx->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(imx->clk_per)) { + int ret = PTR_ERR(imx->clk_per); + + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "failed to get peripheral clock: %d\n", + ret); + + return ret; + } + + imx->chip.ops = &pwm_imx27_ops; + imx->chip.dev = &pdev->dev; + imx->chip.base = -1; + imx->chip.npwm = 1; + + imx->chip.of_xlate = of_pwm_xlate_with_flags; + imx->chip.of_pwm_n_cells = 3; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(imx->mmio_base)) + return PTR_ERR(imx->mmio_base); + + return pwmchip_add(&imx->chip); +} + +static int pwm_imx27_remove(struct platform_device *pdev) +{ + struct pwm_imx27_chip *imx; + + imx = platform_get_drvdata(pdev); + + pwm_imx27_clk_disable_unprepare(&imx->chip); + + return pwmchip_remove(&imx->chip); +} + +static struct platform_driver imx_pwm_driver = { + .driver = { + .name = "pwm-imx27", + .of_match_table = pwm_imx27_dt_ids, + }, + .probe = pwm_imx27_probe, + .remove = pwm_imx27_remove, +}; +module_platform_driver(imx_pwm_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Sascha Hauer "); -- cgit v1.2.3 From 7ca17b207127240b1e4c8687ba7b9077e655336d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 9 Jan 2019 11:27:47 +0300 Subject: pwm: imx: Signedness bug in imx_pwm_get_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "ret" only holds zero and negative error codes. It needs to be signed for the error handling to work. Fixes: 9f4c8f9607c3 ("pwm: imx: Add ipg clock operation") Signed-off-by: Dan Carpenter Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx27.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index 8b8b1c6b7f29..55666cca4cee 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -115,8 +115,9 @@ static void pwm_imx27_get_state(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); - u32 period, prescaler, pwm_clk, ret, val; + u32 period, prescaler, pwm_clk, val; u64 tmp; + int ret; ret = pwm_imx27_clk_prepare_enable(chip); if (ret < 0) -- cgit v1.2.3 From 063755ab1d1c1127adc09703185967862584935b Mon Sep 17 00:00:00 2001 From: Philippe Schenker Date: Fri, 21 Dec 2018 14:46:31 +0100 Subject: mfd: stmpe: Move ADC related defines to MFD header Move defines that are ADC related to the header of the overlying MFD, so they can be used from multiple sub-devices. Signed-off-by: Philippe Schenker Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/touchscreen/stmpe-ts.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 2a78e27b4495..c5d9006588a2 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -49,17 +49,6 @@ #define STMPE_IRQ_TOUCH_DET 0 -#define SAMPLE_TIME(x) ((x & 0xf) << 4) -#define MOD_12B(x) ((x & 0x1) << 3) -#define REF_SEL(x) ((x & 0x1) << 1) -#define ADC_FREQ(x) (x & 0x3) -#define AVE_CTRL(x) ((x & 0x3) << 6) -#define DET_DELAY(x) ((x & 0x7) << 3) -#define SETTLING(x) (x & 0x7) -#define FRACTION_Z(x) (x & 0x7) -#define I_DRIVE(x) (x & 0x1) -#define OP_MODE(x) ((x & 0x7) << 1) - #define STMPE_TS_NAME "stmpe-ts" #define XY_MASK 0xfff @@ -213,9 +202,10 @@ static int stmpe_init_hw(struct stmpe_touch *ts) return ret; } - adc_ctrl1 = SAMPLE_TIME(ts->sample_time) | MOD_12B(ts->mod_12b) | - REF_SEL(ts->ref_sel); - adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff); + adc_ctrl1 = STMPE_SAMPLE_TIME(ts->sample_time) | + STMPE_MOD_12B(ts->mod_12b) | STMPE_REF_SEL(ts->ref_sel); + adc_ctrl1_mask = STMPE_SAMPLE_TIME(0xff) | STMPE_MOD_12B(0xff) | + STMPE_REF_SEL(0xff); ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1, adc_ctrl1_mask, adc_ctrl1); @@ -225,15 +215,17 @@ static int stmpe_init_hw(struct stmpe_touch *ts) } ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2, - ADC_FREQ(0xff), ADC_FREQ(ts->adc_freq)); + STMPE_ADC_FREQ(0xff), STMPE_ADC_FREQ(ts->adc_freq)); if (ret) { dev_err(dev, "Could not setup ADC\n"); return ret; } - tsc_cfg = AVE_CTRL(ts->ave_ctrl) | DET_DELAY(ts->touch_det_delay) | - SETTLING(ts->settling); - tsc_cfg_mask = AVE_CTRL(0xff) | DET_DELAY(0xff) | SETTLING(0xff); + tsc_cfg = STMPE_AVE_CTRL(ts->ave_ctrl) | + STMPE_DET_DELAY(ts->touch_det_delay) | + STMPE_SETTLING(ts->settling); + tsc_cfg_mask = STMPE_AVE_CTRL(0xff) | STMPE_DET_DELAY(0xff) | + STMPE_SETTLING(0xff); ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CFG, tsc_cfg_mask, tsc_cfg); if (ret) { @@ -242,14 +234,14 @@ static int stmpe_init_hw(struct stmpe_touch *ts) } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_FRACTION_Z, - FRACTION_Z(0xff), FRACTION_Z(ts->fraction_z)); + STMPE_FRACTION_Z(0xff), STMPE_FRACTION_Z(ts->fraction_z)); if (ret) { dev_err(dev, "Could not config touch\n"); return ret; } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_I_DRIVE, - I_DRIVE(0xff), I_DRIVE(ts->i_drive)); + STMPE_I_DRIVE(0xff), STMPE_I_DRIVE(ts->i_drive)); if (ret) { dev_err(dev, "Could not config touch\n"); return ret; @@ -263,7 +255,7 @@ static int stmpe_init_hw(struct stmpe_touch *ts) } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CTRL, - OP_MODE(0xff), OP_MODE(OP_MOD_XYZ)); + STMPE_OP_MODE(0xff), STMPE_OP_MODE(OP_MOD_XYZ)); if (ret) { dev_err(dev, "Could not set mode\n"); return ret; -- cgit v1.2.3 From 6377cfa3b857ced301f2079ac97de6c19057ab65 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 21 Dec 2018 14:46:32 +0100 Subject: mfd: stmpe: Preparations for STMPE ADC driver This prepares the MFD for the STMPE ADC driver. This commit introduces devicetree settings that are used by the ADC and adds an init function. Common ADC settings that are shared with the touchscreen driver can now reside in the overlying MFD. Signed-off-by: Stefan Agner Signed-off-by: Max Krummenacher Signed-off-by: Philippe Schenker Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 3 ++- drivers/mfd/stmpe.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8c5dfdce4326..bba159e8eaa4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1204,7 +1204,7 @@ config MFD_STMPE Currently supported devices are: - STMPE811: GPIO, Touchscreen + STMPE811: GPIO, Touchscreen, ADC STMPE1601: GPIO, Keypad STMPE1801: GPIO, Keypad STMPE2401: GPIO, Keypad @@ -1217,6 +1217,7 @@ config MFD_STMPE GPIO: stmpe-gpio Keypad: stmpe-keypad Touchscreen: stmpe-ts + ADC: stmpe-adc menu "STMicroelectronics STMPE Interface Drivers" depends on MFD_STMPE diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 566caca4efd8..f582531a8f3e 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -463,6 +463,28 @@ static const struct mfd_cell stmpe_ts_cell = { .num_resources = ARRAY_SIZE(stmpe_ts_resources), }; +/* + * ADC (STMPE811) + */ + +static struct resource stmpe_adc_resources[] = { + { + .name = "STMPE_TEMP_SENS", + .flags = IORESOURCE_IRQ, + }, + { + .name = "STMPE_ADC", + .flags = IORESOURCE_IRQ, + }, +}; + +static const struct mfd_cell stmpe_adc_cell = { + .name = "stmpe-adc", + .of_compatible = "st,stmpe-adc", + .resources = stmpe_adc_resources, + .num_resources = ARRAY_SIZE(stmpe_adc_resources), +}; + /* * STMPE811 or STMPE610 */ @@ -497,6 +519,11 @@ static struct stmpe_variant_block stmpe811_blocks[] = { .irq = STMPE811_IRQ_TOUCH_DET, .block = STMPE_BLOCK_TOUCHSCREEN, }, + { + .cell = &stmpe_adc_cell, + .irq = STMPE811_IRQ_TEMP_SENS, + .block = STMPE_BLOCK_ADC, + }, }; static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks, @@ -517,6 +544,35 @@ static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks, enable ? 0 : mask); } +int stmpe811_adc_common_init(struct stmpe *stmpe) +{ + int ret; + u8 adc_ctrl1, adc_ctrl1_mask; + + adc_ctrl1 = STMPE_SAMPLE_TIME(stmpe->sample_time) | + STMPE_MOD_12B(stmpe->mod_12b) | + STMPE_REF_SEL(stmpe->ref_sel); + adc_ctrl1_mask = STMPE_SAMPLE_TIME(0xff) | STMPE_MOD_12B(0xff) | + STMPE_REF_SEL(0xff); + + ret = stmpe_set_bits(stmpe, STMPE811_REG_ADC_CTRL1, + adc_ctrl1_mask, adc_ctrl1); + if (ret) { + dev_err(stmpe->dev, "Could not setup ADC\n"); + return ret; + } + + ret = stmpe_set_bits(stmpe, STMPE811_REG_ADC_CTRL2, + STMPE_ADC_FREQ(0xff), STMPE_ADC_FREQ(stmpe->adc_freq)); + if (ret) { + dev_err(stmpe->dev, "Could not setup ADC\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(stmpe811_adc_common_init); + static int stmpe811_get_altfunc(struct stmpe *stmpe, enum stmpe_block block) { /* 0 for touchscreen, 1 for GPIO */ @@ -1325,6 +1381,7 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum) struct device_node *np = ci->dev->of_node; struct stmpe *stmpe; int ret; + u32 val; pdata = devm_kzalloc(ci->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -1342,6 +1399,15 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum) mutex_init(&stmpe->irq_lock); mutex_init(&stmpe->lock); + if (!of_property_read_u32(np, "st,sample-time", &val)) + stmpe->sample_time = val; + if (!of_property_read_u32(np, "st,mod-12b", &val)) + stmpe->mod_12b = val; + if (!of_property_read_u32(np, "st,ref-sel", &val)) + stmpe->ref_sel = val; + if (!of_property_read_u32(np, "st,adc-freq", &val)) + stmpe->adc_freq = val; + stmpe->dev = ci->dev; stmpe->client = ci->client; stmpe->pdata = pdata; @@ -1433,6 +1499,8 @@ int stmpe_remove(struct stmpe *stmpe) if (!IS_ERR(stmpe->vcc)) regulator_disable(stmpe->vcc); + __stmpe_disable(stmpe, STMPE_BLOCK_ADC); + mfd_remove_devices(stmpe->dev); return 0; -- cgit v1.2.3 From 88f29d0f2c8f0d8097dfca9fc3619dfe893e0b15 Mon Sep 17 00:00:00 2001 From: Philippe Schenker Date: Fri, 21 Dec 2018 14:46:33 +0100 Subject: Input: stmpe-ts: preparations for STMPE ADC driver This patch removes common ADC settings in favor to use stmpe811_adc_common_init that is present in MFD. This is necessary in preparation for the stmpe-adc driver, because those two drivers have common settings for the ADC. Signed-off-by: Philippe Schenker Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/touchscreen/stmpe-ts.c | 42 ++++++------------------------------ 1 file changed, 7 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index c5d9006588a2..cf9c9aa39f6e 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -30,8 +30,6 @@ * with touchscreen controller */ #define STMPE_REG_INT_STA 0x0B -#define STMPE_REG_ADC_CTRL1 0x20 -#define STMPE_REG_ADC_CTRL2 0x21 #define STMPE_REG_TSC_CTRL 0x40 #define STMPE_REG_TSC_CFG 0x41 #define STMPE_REG_FIFO_TH 0x4A @@ -58,15 +56,6 @@ * @idev: registered input device * @work: a work item used to scan the device * @dev: a pointer back to the MFD cell struct device* - * @sample_time: ADC converstion time in number of clock. - * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks, - * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks), - * recommended is 4. - * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC) - * @ref_sel: ADC reference source - * (0 -> internal reference, 1 -> external reference) - * @adc_freq: ADC Clock speed - * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz) * @ave_ctrl: Sample average control * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples) * @touch_det_delay: Touch detect interrupt delay @@ -88,10 +77,6 @@ struct stmpe_touch { struct input_dev *idev; struct delayed_work work; struct device *dev; - u8 sample_time; - u8 mod_12b; - u8 ref_sel; - u8 adc_freq; u8 ave_ctrl; u8 touch_det_delay; u8 settling; @@ -192,7 +177,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data) static int stmpe_init_hw(struct stmpe_touch *ts) { int ret; - u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask; + u8 tsc_cfg, tsc_cfg_mask; struct stmpe *stmpe = ts->stmpe; struct device *dev = ts->dev; @@ -202,22 +187,9 @@ static int stmpe_init_hw(struct stmpe_touch *ts) return ret; } - adc_ctrl1 = STMPE_SAMPLE_TIME(ts->sample_time) | - STMPE_MOD_12B(ts->mod_12b) | STMPE_REF_SEL(ts->ref_sel); - adc_ctrl1_mask = STMPE_SAMPLE_TIME(0xff) | STMPE_MOD_12B(0xff) | - STMPE_REF_SEL(0xff); - - ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1, - adc_ctrl1_mask, adc_ctrl1); - if (ret) { - dev_err(dev, "Could not setup ADC\n"); - return ret; - } - - ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2, - STMPE_ADC_FREQ(0xff), STMPE_ADC_FREQ(ts->adc_freq)); + ret = stmpe811_adc_common_init(stmpe); if (ret) { - dev_err(dev, "Could not setup ADC\n"); + stmpe_disable(stmpe, STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC); return ret; } @@ -295,13 +267,13 @@ static void stmpe_ts_get_platform_info(struct platform_device *pdev, if (np) { if (!of_property_read_u32(np, "st,sample-time", &val)) - ts->sample_time = val; + ts->stmpe->sample_time = val; if (!of_property_read_u32(np, "st,mod-12b", &val)) - ts->mod_12b = val; + ts->stmpe->mod_12b = val; if (!of_property_read_u32(np, "st,ref-sel", &val)) - ts->ref_sel = val; + ts->stmpe->ref_sel = val; if (!of_property_read_u32(np, "st,adc-freq", &val)) - ts->adc_freq = val; + ts->stmpe->adc_freq = val; if (!of_property_read_u32(np, "st,ave-ctrl", &val)) ts->ave_ctrl = val; if (!of_property_read_u32(np, "st,touch-det-delay", &val)) -- cgit v1.2.3 From 9f3d084965a5544f096d4f769e274d4c2892079b Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 21 Dec 2018 14:46:34 +0100 Subject: iio: adc: add STMPE ADC driver using IIO framework This adds an ADC driver for the STMPE device using the industrial input/output interface. The driver supports raw reading of values. The driver depends on the MFD STMPE driver. If the touchscreen block is enabled too, only four of the 8 ADC channels are available. Signed-off-by: Stefan Agner Signed-off-by: Max Krummenacher Signed-off-by: Philippe Schenker Reviewed-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/iio/adc/Kconfig | 7 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/stmpe-adc.c | 363 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 371 insertions(+) create mode 100644 drivers/iio/adc/stmpe-adc.c (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7a3ca4ec0cb7..5b72e2963153 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -755,6 +755,13 @@ config STM32_DFSDM_ADC This driver can also be built as a module. If so, the module will be called stm32-dfsdm-adc. +config STMPE_ADC + tristate "STMicroelectronics STMPE ADC driver" + depends on OF && MFD_STMPE + help + Say yes here to build support for ST Microelectronics STMPE + built-in ADC block (stmpe811). + config STX104 tristate "Apex Embedded Systems STX104 driver" depends on PC104 && X86 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 07df37f621bd..6d4e3149ac15 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o obj-$(CONFIG_STM32_ADC) += stm32-adc.o obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o +obj-$(CONFIG_STMPE_ADC) += stmpe-adc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o diff --git a/drivers/iio/adc/stmpe-adc.c b/drivers/iio/adc/stmpe-adc.c new file mode 100644 index 000000000000..37f4b74a5d32 --- /dev/null +++ b/drivers/iio/adc/stmpe-adc.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * STMicroelectronics STMPE811 IIO ADC Driver + * + * 4 channel, 10/12-bit ADC + * + * Copyright (C) 2013-2018 Toradex AG + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STMPE_REG_INT_STA 0x0B +#define STMPE_REG_ADC_INT_EN 0x0E +#define STMPE_REG_ADC_INT_STA 0x0F + +#define STMPE_REG_ADC_CTRL1 0x20 +#define STMPE_REG_ADC_CTRL2 0x21 +#define STMPE_REG_ADC_CAPT 0x22 +#define STMPE_REG_ADC_DATA_CH(channel) (0x30 + 2 * (channel)) + +#define STMPE_REG_TEMP_CTRL 0x60 +#define STMPE_TEMP_CTRL_ENABLE BIT(0) +#define STMPE_TEMP_CTRL_ACQ BIT(1) +#define STMPE_TEMP_CTRL_THRES_EN BIT(3) +#define STMPE_START_ONE_TEMP_CONV (STMPE_TEMP_CTRL_ENABLE | \ + STMPE_TEMP_CTRL_ACQ | \ + STMPE_TEMP_CTRL_THRES_EN) +#define STMPE_REG_TEMP_DATA 0x61 +#define STMPE_REG_TEMP_TH 0x63 +#define STMPE_ADC_LAST_NR 7 +#define STMPE_TEMP_CHANNEL (STMPE_ADC_LAST_NR + 1) + +#define STMPE_ADC_CH(channel) ((1 << (channel)) & 0xff) + +#define STMPE_ADC_TIMEOUT msecs_to_jiffies(1000) + +struct stmpe_adc { + struct stmpe *stmpe; + struct clk *clk; + struct device *dev; + struct mutex lock; + + /* We are allocating plus one for the temperature channel */ + struct iio_chan_spec stmpe_adc_iio_channels[STMPE_ADC_LAST_NR + 2]; + + struct completion completion; + + u8 channel; + u32 value; +}; + +static int stmpe_read_voltage(struct stmpe_adc *info, + struct iio_chan_spec const *chan, int *val) +{ + long ret; + + mutex_lock(&info->lock); + + info->channel = (u8)chan->channel; + + if (info->channel > STMPE_ADC_LAST_NR) { + mutex_unlock(&info->lock); + return -EINVAL; + } + + stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN, + STMPE_ADC_CH(info->channel)); + + stmpe_reg_write(info->stmpe, STMPE_REG_ADC_CAPT, + STMPE_ADC_CH(info->channel)); + + *val = info->value; + + ret = wait_for_completion_interruptible_timeout + (&info->completion, STMPE_ADC_TIMEOUT); + + if (ret <= 0) { + mutex_unlock(&info->lock); + if (ret == 0) + return -ETIMEDOUT; + else + return ret; + } + + *val = info->value; + + mutex_unlock(&info->lock); + + return 0; +} + +static int stmpe_read_temp(struct stmpe_adc *info, + struct iio_chan_spec const *chan, int *val) +{ + long ret; + + mutex_lock(&info->lock); + + info->channel = (u8)chan->channel; + + if (info->channel != STMPE_TEMP_CHANNEL) { + mutex_unlock(&info->lock); + return -EINVAL; + } + + stmpe_reg_write(info->stmpe, STMPE_REG_TEMP_CTRL, + STMPE_START_ONE_TEMP_CONV); + + ret = wait_for_completion_interruptible_timeout + (&info->completion, STMPE_ADC_TIMEOUT); + + if (ret <= 0) { + mutex_unlock(&info->lock); + if (ret == 0) + return -ETIMEDOUT; + else + return ret; + } + + /* + * absolute temp = +V3.3 * value /7.51 [K] + * scale to [milli °C] + */ + *val = ((449960l * info->value) / 1024l) - 273150; + + mutex_unlock(&info->lock); + + return 0; +} + +static int stmpe_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct stmpe_adc *info = iio_priv(indio_dev); + long ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: + + switch (chan->type) { + case IIO_VOLTAGE: + ret = stmpe_read_voltage(info, chan, val); + break; + + case IIO_TEMP: + ret = stmpe_read_temp(info, chan, val); + break; + default: + return -EINVAL; + } + + if (ret < 0) + return ret; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = 3300; + *val2 = info->stmpe->mod_12b ? 12 : 10; + return IIO_VAL_FRACTIONAL_LOG2; + + default: + break; + } + + return -EINVAL; +} + +static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) +{ + struct stmpe_adc *info = (struct stmpe_adc *)dev_id; + u16 data; + + if (info->channel > STMPE_TEMP_CHANNEL) + return IRQ_NONE; + + if (info->channel <= STMPE_ADC_LAST_NR) { + int int_sta; + + int_sta = stmpe_reg_read(info->stmpe, STMPE_REG_ADC_INT_STA); + + /* Is the interrupt relevant */ + if (!(int_sta & STMPE_ADC_CH(info->channel))) + return IRQ_NONE; + + /* Read value */ + stmpe_block_read(info->stmpe, + STMPE_REG_ADC_DATA_CH(info->channel), 2, (u8 *) &data); + + stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA, int_sta); + } else if (info->channel == STMPE_TEMP_CHANNEL) { + /* Read value */ + stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2, + (u8 *) &data); + } + + info->value = (u32) be16_to_cpu(data); + complete(&info->completion); + + return IRQ_HANDLED; +} + +static const struct iio_info stmpe_adc_iio_info = { + .read_raw = &stmpe_read_raw, +}; + +static void stmpe_adc_voltage_chan(struct iio_chan_spec *ics, int chan) +{ + ics->type = IIO_VOLTAGE; + ics->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + ics->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + ics->indexed = 1; + ics->channel = chan; +} + +static void stmpe_adc_temp_chan(struct iio_chan_spec *ics, int chan) +{ + ics->type = IIO_TEMP; + ics->info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED); + ics->indexed = 1; + ics->channel = chan; +} + +static int stmpe_adc_init_hw(struct stmpe_adc *adc) +{ + int ret; + struct stmpe *stmpe = adc->stmpe; + + ret = stmpe_enable(stmpe, STMPE_BLOCK_ADC); + if (ret) { + dev_err(stmpe->dev, "Could not enable clock for ADC\n"); + return ret; + } + + ret = stmpe811_adc_common_init(stmpe); + if (ret) { + stmpe_disable(stmpe, STMPE_BLOCK_ADC); + return ret; + } + + /* use temp irq for each conversion completion */ + stmpe_reg_write(stmpe, STMPE_REG_TEMP_TH, 0); + stmpe_reg_write(stmpe, STMPE_REG_TEMP_TH + 1, 0); + + return 0; +} + +static int stmpe_adc_probe(struct platform_device *pdev) +{ + struct iio_dev *indio_dev; + struct stmpe_adc *info; + struct device_node *np; + u32 norequest_mask = 0; + int irq_temp, irq_adc; + int num_chan = 0; + int i = 0; + int ret; + + irq_adc = platform_get_irq_byname(pdev, "STMPE_ADC"); + if (irq_adc < 0) + return irq_adc; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct stmpe_adc)); + if (!indio_dev) { + dev_err(&pdev->dev, "failed allocating iio device\n"); + return -ENOMEM; + } + + info = iio_priv(indio_dev); + mutex_init(&info->lock); + + init_completion(&info->completion); + ret = devm_request_threaded_irq(&pdev->dev, irq_adc, NULL, + stmpe_adc_isr, IRQF_ONESHOT, + "stmpe-adc", info); + if (ret < 0) { + dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", + irq_adc); + return ret; + } + + irq_temp = platform_get_irq_byname(pdev, "STMPE_TEMP_SENS"); + if (irq_temp >= 0) { + ret = devm_request_threaded_irq(&pdev->dev, irq_temp, NULL, + stmpe_adc_isr, IRQF_ONESHOT, + "stmpe-adc", info); + if (ret < 0) + dev_warn(&pdev->dev, "failed requesting irq for" + " temp sensor, irq = %d\n", irq_temp); + } + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &stmpe_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + info->stmpe = dev_get_drvdata(pdev->dev.parent); + + np = pdev->dev.of_node; + + if (!np) + dev_err(&pdev->dev, "no device tree node found\n"); + + of_property_read_u32(np, "st,norequest-mask", &norequest_mask); + + for_each_clear_bit(i, (unsigned long *) &norequest_mask, + (STMPE_ADC_LAST_NR + 1)) { + stmpe_adc_voltage_chan(&info->stmpe_adc_iio_channels[num_chan], i); + num_chan++; + } + stmpe_adc_temp_chan(&info->stmpe_adc_iio_channels[num_chan], i); + num_chan++; + indio_dev->channels = info->stmpe_adc_iio_channels; + indio_dev->num_channels = num_chan; + + ret = stmpe_adc_init_hw(info); + if (ret) + return ret; + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static int __maybe_unused stmpe_adc_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct stmpe_adc *info = iio_priv(indio_dev); + + stmpe_adc_init_hw(info); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(stmpe_adc_pm_ops, NULL, stmpe_adc_resume); + +static struct platform_driver stmpe_adc_driver = { + .probe = stmpe_adc_probe, + .driver = { + .name = "stmpe-adc", + .pm = &stmpe_adc_pm_ops, + }, +}; + +module_platform_driver(stmpe_adc_driver); + +MODULE_AUTHOR("Stefan Agner "); +MODULE_DESCRIPTION("STMPEXXX ADC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:stmpe-adc"); -- cgit v1.2.3 From 4f821c1002cb236f14d0b4572b0b98fe800178a8 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:44 +0300 Subject: iommu/tegra: gart: Remove pr_fmt and clean up includes Remove unneeded headers inclusion and sort the headers in alphabet order. Remove pr_fmt macro since there is no pr_*() in the code and it doesn't affect dev_*() functions. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index da6a4e357b2b..ff75cf60117b 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -19,22 +19,15 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ -#define pr_fmt(fmt) "%s(): " fmt, __func__ - #include +#include +#include +#include #include -#include -#include +#include #include +#include #include -#include -#include -#include -#include -#include -#include - -#include /* bitmap of the page sizes currently supported */ #define GART_IOMMU_PGSIZES (SZ_4K) -- cgit v1.2.3 From ae95c46dbed56af0e1d106865801bf06e1762c2c Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:45 +0300 Subject: iommu/tegra: gart: Clean up driver probe errors handling Properly clean up allocated resources on the drivers probe failure and remove unneeded checks. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index ff75cf60117b..1cd470b2beea 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -411,9 +411,6 @@ static int tegra_gart_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret; - if (gart_handle) - return -EIO; - BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT); /* the GART memory aperture is required */ @@ -448,8 +445,7 @@ static int tegra_gart_probe(struct platform_device *pdev) ret = iommu_device_register(&gart->iommu); if (ret) { dev_err(dev, "Failed to register IOMMU\n"); - iommu_device_sysfs_remove(&gart->iommu); - return ret; + goto remove_sysfs; } gart->dev = &pdev->dev; @@ -463,7 +459,8 @@ static int tegra_gart_probe(struct platform_device *pdev) gart->savedata = vmalloc(array_size(sizeof(u32), gart->page_count)); if (!gart->savedata) { dev_err(dev, "failed to allocate context save area\n"); - return -ENOMEM; + ret = -ENOMEM; + goto unregister_iommu; } platform_set_drvdata(pdev, gart); @@ -472,6 +469,13 @@ static int tegra_gart_probe(struct platform_device *pdev) gart_handle = gart; return 0; + +unregister_iommu: + iommu_device_unregister(&gart->iommu); +remove_sysfs: + iommu_device_sysfs_remove(&gart->iommu); + + return ret; } static const struct dev_pm_ops tegra_gart_pm_ops = { -- cgit v1.2.3 From 4b6f0ea384f4a39c07fad556a9b4d619759de6c5 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:46 +0300 Subject: iommu/tegra: gart: Ignore devices without IOMMU phandle in DT GART can't handle all devices, hence ignore devices that aren't related to GART. IOMMU phandle must be explicitly assign to devices in the device tree. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 1cd470b2beea..37a76388ff7e 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -345,8 +345,12 @@ static bool gart_iommu_capable(enum iommu_cap cap) static int gart_iommu_add_device(struct device *dev) { - struct iommu_group *group = iommu_group_get_for_dev(dev); + struct iommu_group *group; + if (!dev->iommu_fwspec) + return -ENODEV; + + group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) return PTR_ERR(group); @@ -363,6 +367,12 @@ static void gart_iommu_remove_device(struct device *dev) iommu_device_unlink(&gart_handle->iommu, dev); } +static int gart_iommu_of_xlate(struct device *dev, + struct of_phandle_args *args) +{ + return 0; +} + static const struct iommu_ops gart_iommu_ops = { .capable = gart_iommu_capable, .domain_alloc = gart_iommu_domain_alloc, @@ -376,6 +386,7 @@ static const struct iommu_ops gart_iommu_ops = { .unmap = gart_iommu_unmap, .iova_to_phys = gart_iommu_iova_to_phys, .pgsize_bitmap = GART_IOMMU_PGSIZES, + .of_xlate = gart_iommu_of_xlate, }; static int tegra_gart_suspend(struct device *dev) @@ -441,6 +452,7 @@ static int tegra_gart_probe(struct platform_device *pdev) } iommu_device_set_ops(&gart->iommu, &gart_iommu_ops); + iommu_device_set_fwnode(&gart->iommu, dev->fwnode); ret = iommu_device_register(&gart->iommu); if (ret) { -- cgit v1.2.3 From 1d7ae53b152dbc5ba0a4f6a83ecc42ac66f52d11 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:47 +0300 Subject: iommu: Introduce iotlb_sync_map callback Introduce iotlb_sync_map() callback that is invoked in the end of iommu_map(). This new callback allows IOMMU drivers to avoid syncing after mapping of each contiguous chunk and sync only when the whole mapping is completed, optimizing performance of the mapping operation. Signed-off-by: Dmitry Osipenko Reviewed-by: Robin Murphy Reviewed-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 3ed4db334341..ed0e63f2cd9b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1585,13 +1585,14 @@ static size_t iommu_pgsize(struct iommu_domain *domain, int iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot) { + const struct iommu_ops *ops = domain->ops; unsigned long orig_iova = iova; unsigned int min_pagesz; size_t orig_size = size; phys_addr_t orig_paddr = paddr; int ret = 0; - if (unlikely(domain->ops->map == NULL || + if (unlikely(ops->map == NULL || domain->pgsize_bitmap == 0UL)) return -ENODEV; @@ -1620,7 +1621,7 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n", iova, &paddr, pgsize); - ret = domain->ops->map(domain, iova, paddr, pgsize, prot); + ret = ops->map(domain, iova, paddr, pgsize, prot); if (ret) break; @@ -1629,6 +1630,9 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, size -= pgsize; } + if (ops->iotlb_sync_map) + ops->iotlb_sync_map(domain); + /* unroll mapping in case something went wrong */ if (ret) iommu_unmap(domain, orig_iova, orig_size - size); -- cgit v1.2.3 From 2fc0ac180d0f160cdd5fc69407ca7eb47b3eff99 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:48 +0300 Subject: iommu/tegra: gart: Optimize mapping / unmapping performance Currently GART writes one page entry at a time. More optimal would be to aggregate the writes and flush BUS buffer in the end, this gives map/unmap 10-40% performance boost (depending on size of mapping) in comparison to flushing after each page entry update. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 37a76388ff7e..835fea461c59 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -290,7 +290,6 @@ static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova, } } gart_set_pte(gart, iova, GART_PTE(pfn)); - FLUSH_GART_REGS(gart); spin_unlock_irqrestore(&gart->pte_lock, flags); return 0; } @@ -307,7 +306,6 @@ static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova, spin_lock_irqsave(&gart->pte_lock, flags); gart_set_pte(gart, iova, 0); - FLUSH_GART_REGS(gart); spin_unlock_irqrestore(&gart->pte_lock, flags); return bytes; } @@ -373,6 +371,14 @@ static int gart_iommu_of_xlate(struct device *dev, return 0; } +static void gart_iommu_sync(struct iommu_domain *domain) +{ + struct gart_domain *gart_domain = to_gart_domain(domain); + struct gart_device *gart = gart_domain->gart; + + FLUSH_GART_REGS(gart); +} + static const struct iommu_ops gart_iommu_ops = { .capable = gart_iommu_capable, .domain_alloc = gart_iommu_domain_alloc, @@ -387,6 +393,8 @@ static const struct iommu_ops gart_iommu_ops = { .iova_to_phys = gart_iommu_iova_to_phys, .pgsize_bitmap = GART_IOMMU_PGSIZES, .of_xlate = gart_iommu_of_xlate, + .iotlb_sync_map = gart_iommu_sync, + .iotlb_sync = gart_iommu_sync, }; static int tegra_gart_suspend(struct device *dev) -- cgit v1.2.3 From be4dbdec2bab8635c7a41573668624ee13d83022 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:51 +0300 Subject: memory: tegra: Don't invoke Tegra30+ specific memory timing setup on Tegra20 This fixes irrelevant "tegra-mc 7000f000.memory-controller: no memory timings for RAM code 0 registered" warning message during of kernels boot-up on Tegra20. Fixes: a8d502fd3348 ("memory: tegra: Squash tegra20-mc into common tegra-mc driver") Signed-off-by: Dmitry Osipenko Acked-by: Jon Hunter Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/memory/tegra/mc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 24afc36833bf..b99f3c620f6c 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -664,12 +664,13 @@ static int tegra_mc_probe(struct platform_device *pdev) } isr = tegra_mc_irq; - } - err = tegra_mc_setup_timings(mc); - if (err < 0) { - dev_err(&pdev->dev, "failed to setup timings: %d\n", err); - return err; + err = tegra_mc_setup_timings(mc); + if (err < 0) { + dev_err(&pdev->dev, "failed to setup timings: %d\n", + err); + return err; + } } mc->irq = platform_get_irq(pdev, 0); -- cgit v1.2.3 From 96efa118c03648fdc76acad9ca8fe018a6be7145 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:52 +0300 Subject: memory: tegra: Adapt to Tegra20 device-tree binding changes The tegra20-mc device-tree binding has been changed, GART has been squashed into Memory Controller and now the clock property is mandatory for Tegra20, the DT compatible has been changed as well. Adapt driver to the DT changes. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/memory/tegra/mc.c | 21 ++++++++------------- drivers/memory/tegra/mc.h | 6 ------ 2 files changed, 8 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index b99f3c620f6c..59db13287b47 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -51,7 +51,7 @@ static const struct of_device_id tegra_mc_of_match[] = { #ifdef CONFIG_ARCH_TEGRA_2x_SOC - { .compatible = "nvidia,tegra20-mc", .data = &tegra20_mc_soc }, + { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc }, #endif #ifdef CONFIG_ARCH_TEGRA_3x_SOC { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc }, @@ -638,24 +638,19 @@ static int tegra_mc_probe(struct platform_device *pdev) if (IS_ERR(mc->regs)) return PTR_ERR(mc->regs); + mc->clk = devm_clk_get(&pdev->dev, "mc"); + if (IS_ERR(mc->clk)) { + dev_err(&pdev->dev, "failed to get MC clock: %ld\n", + PTR_ERR(mc->clk)); + return PTR_ERR(mc->clk); + } + #ifdef CONFIG_ARCH_TEGRA_2x_SOC if (mc->soc == &tegra20_mc_soc) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - mc->regs2 = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mc->regs2)) - return PTR_ERR(mc->regs2); - isr = tegra20_mc_irq; } else #endif { - mc->clk = devm_clk_get(&pdev->dev, "mc"); - if (IS_ERR(mc->clk)) { - dev_err(&pdev->dev, "failed to get MC clock: %ld\n", - PTR_ERR(mc->clk)); - return PTR_ERR(mc->clk); - } - err = tegra_mc_setup_latency_allowance(mc); if (err < 0) { dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index 01065f12ebeb..9856f085e487 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -26,18 +26,12 @@ static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) { - if (mc->regs2 && offset >= 0x24) - return readl(mc->regs2 + offset - 0x3c); - return readl(mc->regs + offset); } static inline void mc_writel(struct tegra_mc *mc, u32 value, unsigned long offset) { - if (mc->regs2 && offset >= 0x24) - return writel(value, mc->regs2 + offset - 0x3c); - writel(value, mc->regs + offset); } -- cgit v1.2.3 From b3bb6b858f2a60fe3ac0c3833084386f7dd420e4 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:53 +0300 Subject: memory: tegra: Read client ID on GART page fault With the device tree binding changes, now Memory Controller has access to GART registers. Hence it is now possible to read client ID on GART page fault to get information about what memory client causes the fault. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/memory/tegra/mc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 59db13287b47..ce8cf81b55d7 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -38,6 +38,7 @@ #define MC_ERR_ADR 0x0c +#define MC_GART_ERROR_REQ 0x30 #define MC_DECERR_EMEM_OTHERS_STATUS 0x58 #define MC_SECURITY_VIOLATION_STATUS 0x74 @@ -575,8 +576,15 @@ static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data) break; case MC_INT_INVALID_GART_PAGE: - dev_err_ratelimited(mc->dev, "%s\n", error); - continue; + reg = MC_GART_ERROR_REQ; + value = mc_readl(mc, reg); + + id = (value >> 1) & mc->soc->client_id_mask; + desc = error_names[2]; + + if (value & BIT(0)) + direction = "write"; + break; case MC_INT_SECURITY_VIOLATION: reg = MC_SECURITY_VIOLATION_STATUS; -- cgit v1.2.3 From 59cd046f7f94543540d82216dbbfd8146db43b70 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:54 +0300 Subject: memory: tegra: Use of_device_get_match_data() There is no need to match device with the DT node since it was already matched, use of_device_get_match_data() helper to get the match-data. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/memory/tegra/mc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index ce8cf81b55d7..55ecfb2d8cfd 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -619,23 +620,18 @@ static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data) static int tegra_mc_probe(struct platform_device *pdev) { - const struct of_device_id *match; struct resource *res; struct tegra_mc *mc; void *isr; int err; - match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); - if (!match) - return -ENODEV; - mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); if (!mc) return -ENOMEM; platform_set_drvdata(pdev, mc); spin_lock_init(&mc->lock); - mc->soc = match->data; + mc->soc = of_device_get_match_data(&pdev->dev); mc->dev = &pdev->dev; /* length of MC tick in nanoseconds */ -- cgit v1.2.3 From 45594c683ef780f20f11b1e0018b933b6ff5d9a1 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:55 +0300 Subject: memory: tegra: Use relaxed versions of readl/writel There is no need for inserting of memory barriers to access registers of Memory Controller. Hence use the relaxed versions of the accessors. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/memory/tegra/mc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index 9856f085e487..887a3b07334f 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -26,13 +26,13 @@ static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) { - return readl(mc->regs + offset); + return readl_relaxed(mc->regs + offset); } static inline void mc_writel(struct tegra_mc *mc, u32 value, unsigned long offset) { - writel(value, mc->regs + offset); + writel_relaxed(value, mc->regs + offset); } extern const struct tegra_mc_reset_ops terga_mc_reset_ops_common; -- cgit v1.2.3 From ce2785a75dbca27375f3723f4e697a2a8dc096ee Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:56 +0300 Subject: iommu/tegra: gart: Integrate with Memory Controller driver The device-tree binding has been changed. There is no separate GART device anymore, it is squashed into the Memory Controller. Integrate GART module with the MC in a way it is done for the SMMU on Tegra30+. Signed-off-by: Dmitry Osipenko Signed-off-by: Joerg Roedel --- drivers/iommu/Kconfig | 1 + drivers/iommu/tegra-gart.c | 71 ++++++++++++---------------------------------- drivers/memory/tegra/mc.c | 43 ++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index d9a25715650e..83c099bb7288 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -282,6 +282,7 @@ config ROCKCHIP_IOMMU config TEGRA_IOMMU_GART bool "Tegra GART IOMMU Support" depends on ARCH_TEGRA_2x_SOC + depends on TEGRA_MC select IOMMU_API help Enables support for remapping discontiguous physical memory diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 835fea461c59..b35ffa312a83 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -19,16 +19,17 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include #include #include #include -#include +#include #include #include #include +#include + /* bitmap of the page sizes currently supported */ #define GART_IOMMU_PGSIZES (SZ_4K) @@ -397,9 +398,8 @@ static const struct iommu_ops gart_iommu_ops = { .iotlb_sync = gart_iommu_sync, }; -static int tegra_gart_suspend(struct device *dev) +int tegra_gart_suspend(struct gart_device *gart) { - struct gart_device *gart = dev_get_drvdata(dev); unsigned long iova; u32 *data = gart->savedata; unsigned long flags; @@ -411,9 +411,8 @@ static int tegra_gart_suspend(struct device *dev) return 0; } -static int tegra_gart_resume(struct device *dev) +int tegra_gart_resume(struct gart_device *gart) { - struct gart_device *gart = dev_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&gart->pte_lock, flags); @@ -422,41 +421,33 @@ static int tegra_gart_resume(struct device *dev) return 0; } -static int tegra_gart_probe(struct platform_device *pdev) +struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc) { struct gart_device *gart; - struct resource *res, *res_remap; + struct resource *res_remap; void __iomem *gart_regs; - struct device *dev = &pdev->dev; int ret; BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT); /* the GART memory aperture is required */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - res_remap = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res || !res_remap) { + res_remap = platform_get_resource(to_platform_device(dev), + IORESOURCE_MEM, 1); + if (!res_remap) { dev_err(dev, "GART memory aperture expected\n"); - return -ENXIO; + return ERR_PTR(-ENXIO); } gart = devm_kzalloc(dev, sizeof(*gart), GFP_KERNEL); if (!gart) { dev_err(dev, "failed to allocate gart_device\n"); - return -ENOMEM; - } - - gart_regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!gart_regs) { - dev_err(dev, "failed to remap GART registers\n"); - return -ENXIO; + return ERR_PTR(-ENOMEM); } - ret = iommu_device_sysfs_add(&gart->iommu, &pdev->dev, NULL, - dev_name(&pdev->dev)); + ret = iommu_device_sysfs_add(&gart->iommu, dev, NULL, "gart"); if (ret) { dev_err(dev, "Failed to register IOMMU in sysfs\n"); - return ret; + return ERR_PTR(ret); } iommu_device_set_ops(&gart->iommu, &gart_iommu_ops); @@ -468,7 +459,8 @@ static int tegra_gart_probe(struct platform_device *pdev) goto remove_sysfs; } - gart->dev = &pdev->dev; + gart->dev = dev; + gart_regs = mc->regs + GART_REG_BASE; spin_lock_init(&gart->pte_lock); spin_lock_init(&gart->client_lock); INIT_LIST_HEAD(&gart->client); @@ -483,46 +475,19 @@ static int tegra_gart_probe(struct platform_device *pdev) goto unregister_iommu; } - platform_set_drvdata(pdev, gart); do_gart_setup(gart, NULL); gart_handle = gart; - return 0; + return gart; unregister_iommu: iommu_device_unregister(&gart->iommu); remove_sysfs: iommu_device_sysfs_remove(&gart->iommu); - return ret; -} - -static const struct dev_pm_ops tegra_gart_pm_ops = { - .suspend = tegra_gart_suspend, - .resume = tegra_gart_resume, -}; - -static const struct of_device_id tegra_gart_of_match[] = { - { .compatible = "nvidia,tegra20-gart", }, - { }, -}; - -static struct platform_driver tegra_gart_driver = { - .probe = tegra_gart_probe, - .driver = { - .name = "tegra-gart", - .pm = &tegra_gart_pm_ops, - .of_match_table = tegra_gart_of_match, - .suppress_bind_attrs = true, - }, -}; - -static int __init tegra_gart_init(void) -{ - return platform_driver_register(&tegra_gart_driver); + return ERR_PTR(ret); } -subsys_initcall(tegra_gart_init); module_param(gart_debug, bool, 0644); MODULE_PARM_DESC(gart_debug, "Enable GART debugging"); diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 55ecfb2d8cfd..e684e234361a 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -702,13 +702,56 @@ static int tegra_mc_probe(struct platform_device *pdev) PTR_ERR(mc->smmu)); } + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { + mc->gart = tegra_gart_probe(&pdev->dev, mc); + if (IS_ERR(mc->gart)) { + dev_err(&pdev->dev, "failed to probe GART: %ld\n", + PTR_ERR(mc->gart)); + mc->gart = NULL; + } + } + + return 0; +} + +static int tegra_mc_suspend(struct device *dev) +{ + struct tegra_mc *mc = dev_get_drvdata(dev); + int err; + + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { + err = tegra_gart_suspend(mc->gart); + if (err) + return err; + } + return 0; } +static int tegra_mc_resume(struct device *dev) +{ + struct tegra_mc *mc = dev_get_drvdata(dev); + int err; + + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { + err = tegra_gart_resume(mc->gart); + if (err) + return err; + } + + return 0; +} + +static const struct dev_pm_ops tegra_mc_pm_ops = { + .suspend = tegra_mc_suspend, + .resume = tegra_mc_resume, +}; + static struct platform_driver tegra_mc_driver = { .driver = { .name = "tegra-mc", .of_match_table = tegra_mc_of_match, + .pm = &tegra_mc_pm_ops, .suppress_bind_attrs = true, }, .prevent_deferred_probe = true, -- cgit v1.2.3 From 568ece5bab24d41bec4d1610439277032840a133 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:57 +0300 Subject: memory: tegra: Do not try to probe SMMU on Tegra20 Tegra20 doesn't have SMMU. Move out checking of the SMMU presence from the SMMU driver into the Memory Controller driver. This change makes code consistent in regards to how GART/SMMU presence checking is performed. Signed-off-by: Dmitry Osipenko Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 4 ---- drivers/memory/tegra/mc.c | 6 ++++-- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 3a5c7dc6dc57..5182c7d6171e 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -982,10 +982,6 @@ struct tegra_smmu *tegra_smmu_probe(struct device *dev, u32 value; int err; - /* This can happen on Tegra20 which doesn't have an SMMU */ - if (!soc) - return NULL; - smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); if (!smmu) return ERR_PTR(-ENOMEM); diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index e684e234361a..3545868c51c0 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -695,11 +695,13 @@ static int tegra_mc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to register reset controller: %d\n", err); - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU) && mc->soc->smmu) { mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); - if (IS_ERR(mc->smmu)) + if (IS_ERR(mc->smmu)) { dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", PTR_ERR(mc->smmu)); + mc->smmu = NULL; + } } if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { -- cgit v1.2.3 From 33ea002aadd9cbf1836a13c71e424f113bce635a Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:58 +0300 Subject: memory: tegra: Do not ask for IRQ sharing Memory Controller driver never shared IRQ with any other driver and very unlikely that it will. Hence there is no need to request IRQ sharing and the corresponding flag can be dropped safely. Signed-off-by: Dmitry Osipenko Signed-off-by: Joerg Roedel --- drivers/memory/tegra/mc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 3545868c51c0..570da2129fa6 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -682,7 +682,7 @@ static int tegra_mc_probe(struct platform_device *pdev) mc_writel(mc, mc->soc->intmask, MC_INTMASK); - err = devm_request_irq(&pdev->dev, mc->irq, isr, IRQF_SHARED, + err = devm_request_irq(&pdev->dev, mc->irq, isr, 0, dev_name(&pdev->dev), mc); if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, -- cgit v1.2.3 From f2dcded1be0d024870b5a4ef8e4a587857f303b4 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:38:59 +0300 Subject: memory: tegra: Clean up error messages Make all messages to start with a lower case and don't unnecessarily go over 80 chars in the code. Signed-off-by: Dmitry Osipenko Signed-off-by: Joerg Roedel --- drivers/memory/tegra/mc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 570da2129fa6..0a53598d982f 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -163,7 +163,7 @@ static int tegra_mc_hotreset_assert(struct reset_controller_dev *rcdev, /* block clients DMA requests */ err = rst_ops->block_dma(mc, rst); if (err) { - dev_err(mc->dev, "Failed to block %s DMA: %d\n", + dev_err(mc->dev, "failed to block %s DMA: %d\n", rst->name, err); return err; } @@ -173,7 +173,7 @@ static int tegra_mc_hotreset_assert(struct reset_controller_dev *rcdev, /* wait for completion of the outstanding DMA requests */ while (!rst_ops->dma_idling(mc, rst)) { if (!retries--) { - dev_err(mc->dev, "Failed to flush %s DMA\n", + dev_err(mc->dev, "failed to flush %s DMA\n", rst->name); return -EBUSY; } @@ -186,7 +186,7 @@ static int tegra_mc_hotreset_assert(struct reset_controller_dev *rcdev, /* clear clients DMA requests sitting before arbitration */ err = rst_ops->hotreset_assert(mc, rst); if (err) { - dev_err(mc->dev, "Failed to hot reset %s: %d\n", + dev_err(mc->dev, "failed to hot reset %s: %d\n", rst->name, err); return err; } @@ -215,7 +215,7 @@ static int tegra_mc_hotreset_deassert(struct reset_controller_dev *rcdev, /* take out client from hot reset */ err = rst_ops->hotreset_deassert(mc, rst); if (err) { - dev_err(mc->dev, "Failed to deassert hot reset %s: %d\n", + dev_err(mc->dev, "failed to deassert hot reset %s: %d\n", rst->name, err); return err; } @@ -225,7 +225,7 @@ static int tegra_mc_hotreset_deassert(struct reset_controller_dev *rcdev, /* allow new DMA requests to proceed to arbitration */ err = rst_ops->unblock_dma(mc, rst); if (err) { - dev_err(mc->dev, "Failed to unblock %s DMA : %d\n", + dev_err(mc->dev, "failed to unblock %s DMA : %d\n", rst->name, err); return err; } @@ -657,7 +657,8 @@ static int tegra_mc_probe(struct platform_device *pdev) { err = tegra_mc_setup_latency_allowance(mc); if (err < 0) { - dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", + dev_err(&pdev->dev, + "failed to setup latency allowance: %d\n", err); return err; } @@ -678,7 +679,7 @@ static int tegra_mc_probe(struct platform_device *pdev) return mc->irq; } - WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n"); + WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n"); mc_writel(mc, mc->soc->intmask, MC_INTMASK); -- cgit v1.2.3 From c3086fad2755f5e446f6a69fda3b2a8c16a1b5ce Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:39:00 +0300 Subject: iommu/tegra: gart: Fix spinlock recursion Fix spinlock recursion bug that happens on IOMMU domain destruction if any of the allocated domains have devices attached to them. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index b35ffa312a83..a7a9400e0cd8 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -197,25 +197,33 @@ fail: return err; } -static void gart_iommu_detach_dev(struct iommu_domain *domain, - struct device *dev) +static void __gart_iommu_detach_dev(struct iommu_domain *domain, + struct device *dev) { struct gart_domain *gart_domain = to_gart_domain(domain); struct gart_device *gart = gart_domain->gart; struct gart_client *c; - spin_lock(&gart->client_lock); - list_for_each_entry(c, &gart->client, list) { if (c->dev == dev) { list_del(&c->list); devm_kfree(gart->dev, c); dev_dbg(gart->dev, "Detached %s\n", dev_name(dev)); - goto out; + return; } } - dev_err(gart->dev, "Couldn't find\n"); -out: + + dev_err(gart->dev, "Couldn't find %s to detach\n", dev_name(dev)); +} + +static void gart_iommu_detach_dev(struct iommu_domain *domain, + struct device *dev) +{ + struct gart_domain *gart_domain = to_gart_domain(domain); + struct gart_device *gart = gart_domain->gart; + + spin_lock(&gart->client_lock); + __gart_iommu_detach_dev(domain, dev); spin_unlock(&gart->client_lock); } @@ -255,7 +263,7 @@ static void gart_iommu_domain_free(struct iommu_domain *domain) struct gart_client *c; list_for_each_entry(c, &gart->client, list) - gart_iommu_detach_dev(domain, c->dev); + __gart_iommu_detach_dev(domain, c->dev); } spin_unlock(&gart->client_lock); } -- cgit v1.2.3 From 8e924910dd07f1614fe534f8bdfdc17f7de3d68b Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:39:01 +0300 Subject: iommu/tegra: gart: Fix NULL pointer dereference Fix NULL pointer dereference on IOMMU domain destruction that happens because clients list is being iterated unsafely and its elements are getting deleted during the iteration. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index a7a9400e0cd8..7fdd8b12efd5 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -260,9 +260,9 @@ static void gart_iommu_domain_free(struct iommu_domain *domain) if (gart) { spin_lock(&gart->client_lock); if (!list_empty(&gart->client)) { - struct gart_client *c; + struct gart_client *c, *tmp; - list_for_each_entry(c, &gart->client, list) + list_for_each_entry_safe(c, tmp, &gart->client, list) __gart_iommu_detach_dev(domain, c->dev); } spin_unlock(&gart->client_lock); -- cgit v1.2.3 From 7d849b7b40b9b3f574f50bbf44503b38e319fca5 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:39:02 +0300 Subject: iommu/tegra: gart: Allow only one active domain at a time GART has a single address space that is shared by all devices, hence only one domain could be active at a time. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 7fdd8b12efd5..71ff22be9560 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -57,6 +57,7 @@ struct gart_device { spinlock_t pte_lock; /* for pagetable */ struct list_head client; spinlock_t client_lock; /* for client list */ + struct iommu_domain *active_domain; /* current active domain */ struct device *dev; struct iommu_device iommu; /* IOMMU Core handle */ @@ -186,6 +187,12 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain, goto fail; } } + if (gart->active_domain && gart->active_domain != domain) { + dev_err(gart->dev, "Only one domain can be active at a time\n"); + err = -EINVAL; + goto fail; + } + gart->active_domain = domain; list_add(&client->list, &gart->client); spin_unlock(&gart->client_lock); dev_dbg(gart->dev, "Attached %s\n", dev_name(dev)); @@ -208,6 +215,8 @@ static void __gart_iommu_detach_dev(struct iommu_domain *domain, if (c->dev == dev) { list_del(&c->list); devm_kfree(gart->dev, c); + if (list_empty(&gart->client)) + gart->active_domain = NULL; dev_dbg(gart->dev, "Detached %s\n", dev_name(dev)); return; } -- cgit v1.2.3 From 167d67d550b9e94207578679c3a6feef78449f38 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:39:03 +0300 Subject: iommu/tegra: gart: Don't use managed resources GART is a part of the Memory Controller driver that is always built-in, hence there is no benefit from the use of managed resources. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 71ff22be9560..2e0e6aff8f70 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -173,7 +173,7 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain, struct gart_client *client, *c; int err = 0; - client = devm_kzalloc(gart->dev, sizeof(*c), GFP_KERNEL); + client = kzalloc(sizeof(*c), GFP_KERNEL); if (!client) return -ENOMEM; client->dev = dev; @@ -199,7 +199,7 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain, return 0; fail: - devm_kfree(gart->dev, client); + kfree(client); spin_unlock(&gart->client_lock); return err; } @@ -214,7 +214,7 @@ static void __gart_iommu_detach_dev(struct iommu_domain *domain, list_for_each_entry(c, &gart->client, list) { if (c->dev == dev) { list_del(&c->list); - devm_kfree(gart->dev, c); + kfree(c); if (list_empty(&gart->client)) gart->active_domain = NULL; dev_dbg(gart->dev, "Detached %s\n", dev_name(dev)); @@ -455,7 +455,7 @@ struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc) return ERR_PTR(-ENXIO); } - gart = devm_kzalloc(dev, sizeof(*gart), GFP_KERNEL); + gart = kzalloc(sizeof(*gart), GFP_KERNEL); if (!gart) { dev_err(dev, "failed to allocate gart_device\n"); return ERR_PTR(-ENOMEM); @@ -464,7 +464,7 @@ struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc) ret = iommu_device_sysfs_add(&gart->iommu, dev, NULL, "gart"); if (ret) { dev_err(dev, "Failed to register IOMMU in sysfs\n"); - return ERR_PTR(ret); + goto free_gart; } iommu_device_set_ops(&gart->iommu, &gart_iommu_ops); @@ -502,6 +502,8 @@ unregister_iommu: iommu_device_unregister(&gart->iommu); remove_sysfs: iommu_device_sysfs_remove(&gart->iommu); +free_gart: + kfree(gart); return ERR_PTR(ret); } -- cgit v1.2.3 From 5dd82cdb36880e0c87b58a002a0513cfbc18552a Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:39:04 +0300 Subject: iommu/tegra: gart: Prepend error/debug messages with "gart:" GART became a part of Memory Controller, hence now the drivers device is Memory Controller and not GART. As a result all printed messages are prepended with the "tegra-mc 7000f000.memory-controller:", so let's prepend GART's messages with "gart:" in order to differentiate them from the MC. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 2e0e6aff8f70..a3ce6918577d 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -19,6 +19,8 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ +#define dev_fmt(fmt) "gart: " fmt + #include #include #include -- cgit v1.2.3 From cc0e1205766b8be1e6f7985991ad80c8c5e791c2 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:39:05 +0300 Subject: iommu/tegra: gart: Don't detach devices from inactive domains There could be unlimited number of allocated domains, but only one domain can be active at a time. Hence devices must be detached only from the active domain. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index a3ce6918577d..74c9be13f043 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -171,7 +171,7 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) { struct gart_domain *gart_domain = to_gart_domain(domain); - struct gart_device *gart = gart_domain->gart; + struct gart_device *gart = gart_handle; struct gart_client *client, *c; int err = 0; @@ -195,6 +195,7 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain, goto fail; } gart->active_domain = domain; + gart_domain->gart = gart; list_add(&client->list, &gart->client); spin_unlock(&gart->client_lock); dev_dbg(gart->dev, "Attached %s\n", dev_name(dev)); @@ -217,8 +218,10 @@ static void __gart_iommu_detach_dev(struct iommu_domain *domain, if (c->dev == dev) { list_del(&c->list); kfree(c); - if (list_empty(&gart->client)) + if (list_empty(&gart->client)) { gart->active_domain = NULL; + gart_domain->gart = NULL; + } dev_dbg(gart->dev, "Detached %s\n", dev_name(dev)); return; } @@ -254,7 +257,6 @@ static struct iommu_domain *gart_iommu_domain_alloc(unsigned type) if (!gart_domain) return NULL; - gart_domain->gart = gart; gart_domain->domain.geometry.aperture_start = gart->iovmm_base; gart_domain->domain.geometry.aperture_end = gart->iovmm_base + gart->page_count * GART_PAGE_SIZE - 1; -- cgit v1.2.3 From e7e2367041179318591d3a656f146e20418f99bb Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:39:06 +0300 Subject: iommu/tegra: gart: Simplify clients-tracking code GART is a simple IOMMU provider that has single address space. There is no need to setup global clients list and manage it for tracking of the active domain, hence lot's of code could be safely removed and replaced with a simpler alternative. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 155 ++++++++++++--------------------------------- 1 file changed, 40 insertions(+), 115 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 74c9be13f043..ad348c61d5e7 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -46,30 +45,20 @@ #define GART_PAGE_MASK \ (~(GART_PAGE_SIZE - 1) & ~GART_ENTRY_PHYS_ADDR_VALID) -struct gart_client { - struct device *dev; - struct list_head list; -}; - struct gart_device { void __iomem *regs; u32 *savedata; u32 page_count; /* total remappable size */ dma_addr_t iovmm_base; /* offset to vmm_area */ spinlock_t pte_lock; /* for pagetable */ - struct list_head client; - spinlock_t client_lock; /* for client list */ + spinlock_t dom_lock; /* for active domain */ + unsigned int active_devices; /* number of active devices */ struct iommu_domain *active_domain; /* current active domain */ struct device *dev; struct iommu_device iommu; /* IOMMU Core handle */ }; -struct gart_domain { - struct iommu_domain domain; /* generic domain handle */ - struct gart_device *gart; /* link to gart device */ -}; - static struct gart_device *gart_handle; /* unique for a system */ static bool gart_debug; @@ -77,11 +66,6 @@ static bool gart_debug; #define GART_PTE(_pfn) \ (GART_ENTRY_PHYS_ADDR_VALID | ((_pfn) << PAGE_SHIFT)) -static struct gart_domain *to_gart_domain(struct iommu_domain *dom) -{ - return container_of(dom, struct gart_domain, domain); -} - /* * Any interaction between any block on PPSB and a block on APB or AHB * must have these read-back to ensure the APB/AHB bus transaction is @@ -170,125 +154,70 @@ static inline bool gart_iova_range_valid(struct gart_device *gart, static int gart_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) { - struct gart_domain *gart_domain = to_gart_domain(domain); struct gart_device *gart = gart_handle; - struct gart_client *client, *c; - int err = 0; - - client = kzalloc(sizeof(*c), GFP_KERNEL); - if (!client) - return -ENOMEM; - client->dev = dev; - - spin_lock(&gart->client_lock); - list_for_each_entry(c, &gart->client, list) { - if (c->dev == dev) { - dev_err(gart->dev, - "%s is already attached\n", dev_name(dev)); - err = -EINVAL; - goto fail; - } - } - if (gart->active_domain && gart->active_domain != domain) { - dev_err(gart->dev, "Only one domain can be active at a time\n"); - err = -EINVAL; - goto fail; - } - gart->active_domain = domain; - gart_domain->gart = gart; - list_add(&client->list, &gart->client); - spin_unlock(&gart->client_lock); - dev_dbg(gart->dev, "Attached %s\n", dev_name(dev)); - return 0; + int ret = 0; -fail: - kfree(client); - spin_unlock(&gart->client_lock); - return err; -} + spin_lock(&gart->dom_lock); -static void __gart_iommu_detach_dev(struct iommu_domain *domain, - struct device *dev) -{ - struct gart_domain *gart_domain = to_gart_domain(domain); - struct gart_device *gart = gart_domain->gart; - struct gart_client *c; - - list_for_each_entry(c, &gart->client, list) { - if (c->dev == dev) { - list_del(&c->list); - kfree(c); - if (list_empty(&gart->client)) { - gart->active_domain = NULL; - gart_domain->gart = NULL; - } - dev_dbg(gart->dev, "Detached %s\n", dev_name(dev)); - return; - } + if (gart->active_domain && gart->active_domain != domain) { + ret = -EBUSY; + } else if (dev->archdata.iommu != domain) { + dev->archdata.iommu = domain; + gart->active_domain = domain; + gart->active_devices++; } - dev_err(gart->dev, "Couldn't find %s to detach\n", dev_name(dev)); + spin_unlock(&gart->dom_lock); + + return ret; } static void gart_iommu_detach_dev(struct iommu_domain *domain, struct device *dev) { - struct gart_domain *gart_domain = to_gart_domain(domain); - struct gart_device *gart = gart_domain->gart; + struct gart_device *gart = gart_handle; + + spin_lock(&gart->dom_lock); - spin_lock(&gart->client_lock); - __gart_iommu_detach_dev(domain, dev); - spin_unlock(&gart->client_lock); + if (dev->archdata.iommu == domain) { + dev->archdata.iommu = NULL; + + if (--gart->active_devices == 0) + gart->active_domain = NULL; + } + + spin_unlock(&gart->dom_lock); } static struct iommu_domain *gart_iommu_domain_alloc(unsigned type) { - struct gart_domain *gart_domain; - struct gart_device *gart; + struct gart_device *gart = gart_handle; + struct iommu_domain *domain; if (type != IOMMU_DOMAIN_UNMANAGED) return NULL; - gart = gart_handle; - if (!gart) - return NULL; - - gart_domain = kzalloc(sizeof(*gart_domain), GFP_KERNEL); - if (!gart_domain) - return NULL; - - gart_domain->domain.geometry.aperture_start = gart->iovmm_base; - gart_domain->domain.geometry.aperture_end = gart->iovmm_base + + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (domain) { + domain->geometry.aperture_start = gart->iovmm_base; + domain->geometry.aperture_end = gart->iovmm_base + gart->page_count * GART_PAGE_SIZE - 1; - gart_domain->domain.geometry.force_aperture = true; + domain->geometry.force_aperture = true; + } - return &gart_domain->domain; + return domain; } static void gart_iommu_domain_free(struct iommu_domain *domain) { - struct gart_domain *gart_domain = to_gart_domain(domain); - struct gart_device *gart = gart_domain->gart; - - if (gart) { - spin_lock(&gart->client_lock); - if (!list_empty(&gart->client)) { - struct gart_client *c, *tmp; - - list_for_each_entry_safe(c, tmp, &gart->client, list) - __gart_iommu_detach_dev(domain, c->dev); - } - spin_unlock(&gart->client_lock); - } - - kfree(gart_domain); + WARN_ON(gart_handle->active_domain == domain); + kfree(domain); } static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t pa, size_t bytes, int prot) { - struct gart_domain *gart_domain = to_gart_domain(domain); - struct gart_device *gart = gart_domain->gart; + struct gart_device *gart = gart_handle; unsigned long flags; unsigned long pfn; unsigned long pte; @@ -319,8 +248,7 @@ static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova, static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t bytes) { - struct gart_domain *gart_domain = to_gart_domain(domain); - struct gart_device *gart = gart_domain->gart; + struct gart_device *gart = gart_handle; unsigned long flags; if (!gart_iova_range_valid(gart, iova, bytes)) @@ -335,8 +263,7 @@ static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova, static phys_addr_t gart_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) { - struct gart_domain *gart_domain = to_gart_domain(domain); - struct gart_device *gart = gart_domain->gart; + struct gart_device *gart = gart_handle; unsigned long pte; phys_addr_t pa; unsigned long flags; @@ -395,8 +322,7 @@ static int gart_iommu_of_xlate(struct device *dev, static void gart_iommu_sync(struct iommu_domain *domain) { - struct gart_domain *gart_domain = to_gart_domain(domain); - struct gart_device *gart = gart_domain->gart; + struct gart_device *gart = gart_handle; FLUSH_GART_REGS(gart); } @@ -483,8 +409,7 @@ struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc) gart->dev = dev; gart_regs = mc->regs + GART_REG_BASE; spin_lock_init(&gart->pte_lock); - spin_lock_init(&gart->client_lock); - INIT_LIST_HEAD(&gart->client); + spin_lock_init(&gart->dom_lock); gart->regs = gart_regs; gart->iovmm_base = (dma_addr_t)res_remap->start; gart->page_count = (resource_size(res_remap) >> GART_PAGE_SHIFT); -- cgit v1.2.3 From 707223095ccf1fd81c9fa5346239b79127c322c2 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Dec 2018 23:39:07 +0300 Subject: iommu/tegra: gart: Perform code refactoring Removed redundant safety-checks in the code and some debug code that isn't actually very useful for debugging, like enormous pagetable dump on each fault. The majority of the changes are code reshuffling, variables/whitespaces clean up and removal of debug messages that duplicate messages of the IOMMU-core. Now the GART translation is kept disabled while GART is suspended. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 253 +++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 148 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index ad348c61d5e7..4d8057916552 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -1,5 +1,5 @@ /* - * IOMMU API for GART in Tegra20 + * IOMMU API for Graphics Address Relocation Table on Tegra20 * * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. * @@ -31,70 +31,63 @@ #include -/* bitmap of the page sizes currently supported */ -#define GART_IOMMU_PGSIZES (SZ_4K) - #define GART_REG_BASE 0x24 #define GART_CONFIG (0x24 - GART_REG_BASE) #define GART_ENTRY_ADDR (0x28 - GART_REG_BASE) #define GART_ENTRY_DATA (0x2c - GART_REG_BASE) -#define GART_ENTRY_PHYS_ADDR_VALID (1 << 31) + +#define GART_ENTRY_PHYS_ADDR_VALID BIT(31) #define GART_PAGE_SHIFT 12 #define GART_PAGE_SIZE (1 << GART_PAGE_SHIFT) -#define GART_PAGE_MASK \ - (~(GART_PAGE_SIZE - 1) & ~GART_ENTRY_PHYS_ADDR_VALID) +#define GART_PAGE_MASK GENMASK(30, GART_PAGE_SHIFT) + +/* bitmap of the page sizes currently supported */ +#define GART_IOMMU_PGSIZES (GART_PAGE_SIZE) struct gart_device { void __iomem *regs; u32 *savedata; - u32 page_count; /* total remappable size */ - dma_addr_t iovmm_base; /* offset to vmm_area */ + unsigned long iovmm_base; /* offset to vmm_area start */ + unsigned long iovmm_end; /* offset to vmm_area end */ spinlock_t pte_lock; /* for pagetable */ spinlock_t dom_lock; /* for active domain */ unsigned int active_devices; /* number of active devices */ struct iommu_domain *active_domain; /* current active domain */ - struct device *dev; - struct iommu_device iommu; /* IOMMU Core handle */ + struct device *dev; }; static struct gart_device *gart_handle; /* unique for a system */ static bool gart_debug; -#define GART_PTE(_pfn) \ - (GART_ENTRY_PHYS_ADDR_VALID | ((_pfn) << PAGE_SHIFT)) - /* * Any interaction between any block on PPSB and a block on APB or AHB * must have these read-back to ensure the APB/AHB bus transaction is * complete before initiating activity on the PPSB block. */ -#define FLUSH_GART_REGS(gart) ((void)readl((gart)->regs + GART_CONFIG)) +#define FLUSH_GART_REGS(gart) readl_relaxed((gart)->regs + GART_CONFIG) #define for_each_gart_pte(gart, iova) \ for (iova = gart->iovmm_base; \ - iova < gart->iovmm_base + GART_PAGE_SIZE * gart->page_count; \ + iova < gart->iovmm_end; \ iova += GART_PAGE_SIZE) static inline void gart_set_pte(struct gart_device *gart, - unsigned long offs, u32 pte) + unsigned long iova, unsigned long pte) { - writel(offs, gart->regs + GART_ENTRY_ADDR); - writel(pte, gart->regs + GART_ENTRY_DATA); - - dev_dbg(gart->dev, "%s %08lx:%08x\n", - pte ? "map" : "unmap", offs, pte & GART_PAGE_MASK); + writel_relaxed(iova, gart->regs + GART_ENTRY_ADDR); + writel_relaxed(pte, gart->regs + GART_ENTRY_DATA); } static inline unsigned long gart_read_pte(struct gart_device *gart, - unsigned long offs) + unsigned long iova) { unsigned long pte; - writel(offs, gart->regs + GART_ENTRY_ADDR); - pte = readl(gart->regs + GART_ENTRY_DATA); + writel_relaxed(iova, gart->regs + GART_ENTRY_ADDR); + pte = readl_relaxed(gart->regs + GART_ENTRY_DATA); return pte; } @@ -106,49 +99,20 @@ static void do_gart_setup(struct gart_device *gart, const u32 *data) for_each_gart_pte(gart, iova) gart_set_pte(gart, iova, data ? *(data++) : 0); - writel(1, gart->regs + GART_CONFIG); + writel_relaxed(1, gart->regs + GART_CONFIG); FLUSH_GART_REGS(gart); } -#ifdef DEBUG -static void gart_dump_table(struct gart_device *gart) -{ - unsigned long iova; - unsigned long flags; - - spin_lock_irqsave(&gart->pte_lock, flags); - for_each_gart_pte(gart, iova) { - unsigned long pte; - - pte = gart_read_pte(gart, iova); - - dev_dbg(gart->dev, "%s %08lx:%08lx\n", - (GART_ENTRY_PHYS_ADDR_VALID & pte) ? "v" : " ", - iova, pte & GART_PAGE_MASK); - } - spin_unlock_irqrestore(&gart->pte_lock, flags); -} -#else -static inline void gart_dump_table(struct gart_device *gart) +static inline bool gart_iova_range_invalid(struct gart_device *gart, + unsigned long iova, size_t bytes) { + return unlikely(iova < gart->iovmm_base || bytes != GART_PAGE_SIZE || + iova + bytes > gart->iovmm_end); } -#endif -static inline bool gart_iova_range_valid(struct gart_device *gart, - unsigned long iova, size_t bytes) +static inline bool gart_pte_valid(struct gart_device *gart, unsigned long iova) { - unsigned long iova_start, iova_end, gart_start, gart_end; - - iova_start = iova; - iova_end = iova_start + bytes - 1; - gart_start = gart->iovmm_base; - gart_end = gart_start + gart->page_count * GART_PAGE_SIZE - 1; - - if (iova_start < gart_start) - return false; - if (iova_end > gart_end) - return false; - return true; + return !!(gart_read_pte(gart, iova) & GART_ENTRY_PHYS_ADDR_VALID); } static int gart_iommu_attach_dev(struct iommu_domain *domain, @@ -191,7 +155,6 @@ static void gart_iommu_detach_dev(struct iommu_domain *domain, static struct iommu_domain *gart_iommu_domain_alloc(unsigned type) { - struct gart_device *gart = gart_handle; struct iommu_domain *domain; if (type != IOMMU_DOMAIN_UNMANAGED) @@ -199,9 +162,8 @@ static struct iommu_domain *gart_iommu_domain_alloc(unsigned type) domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (domain) { - domain->geometry.aperture_start = gart->iovmm_base; - domain->geometry.aperture_end = gart->iovmm_base + - gart->page_count * GART_PAGE_SIZE - 1; + domain->geometry.aperture_start = gart_handle->iovmm_base; + domain->geometry.aperture_end = gart_handle->iovmm_end - 1; domain->geometry.force_aperture = true; } @@ -214,34 +176,45 @@ static void gart_iommu_domain_free(struct iommu_domain *domain) kfree(domain); } +static inline int __gart_iommu_map(struct gart_device *gart, unsigned long iova, + unsigned long pa) +{ + if (unlikely(gart_debug && gart_pte_valid(gart, iova))) { + dev_err(gart->dev, "Page entry is in-use\n"); + return -EINVAL; + } + + gart_set_pte(gart, iova, GART_ENTRY_PHYS_ADDR_VALID | pa); + + return 0; +} + static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t pa, size_t bytes, int prot) { struct gart_device *gart = gart_handle; - unsigned long flags; - unsigned long pfn; - unsigned long pte; + int ret; - if (!gart_iova_range_valid(gart, iova, bytes)) + if (gart_iova_range_invalid(gart, iova, bytes)) return -EINVAL; - spin_lock_irqsave(&gart->pte_lock, flags); - pfn = __phys_to_pfn(pa); - if (!pfn_valid(pfn)) { - dev_err(gart->dev, "Invalid page: %pa\n", &pa); - spin_unlock_irqrestore(&gart->pte_lock, flags); + spin_lock(&gart->pte_lock); + ret = __gart_iommu_map(gart, iova, (unsigned long)pa); + spin_unlock(&gart->pte_lock); + + return ret; +} + +static inline int __gart_iommu_unmap(struct gart_device *gart, + unsigned long iova) +{ + if (unlikely(gart_debug && !gart_pte_valid(gart, iova))) { + dev_err(gart->dev, "Page entry is invalid\n"); return -EINVAL; } - if (gart_debug) { - pte = gart_read_pte(gart, iova); - if (pte & GART_ENTRY_PHYS_ADDR_VALID) { - spin_unlock_irqrestore(&gart->pte_lock, flags); - dev_err(gart->dev, "Page entry is in-use\n"); - return -EBUSY; - } - } - gart_set_pte(gart, iova, GART_PTE(pfn)); - spin_unlock_irqrestore(&gart->pte_lock, flags); + + gart_set_pte(gart, iova, 0); + return 0; } @@ -249,15 +222,16 @@ static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t bytes) { struct gart_device *gart = gart_handle; - unsigned long flags; + int err; - if (!gart_iova_range_valid(gart, iova, bytes)) + if (gart_iova_range_invalid(gart, iova, bytes)) return 0; - spin_lock_irqsave(&gart->pte_lock, flags); - gart_set_pte(gart, iova, 0); - spin_unlock_irqrestore(&gart->pte_lock, flags); - return bytes; + spin_lock(&gart->pte_lock); + err = __gart_iommu_unmap(gart, iova); + spin_unlock(&gart->pte_lock); + + return err ? 0 : bytes; } static phys_addr_t gart_iommu_iova_to_phys(struct iommu_domain *domain, @@ -265,24 +239,15 @@ static phys_addr_t gart_iommu_iova_to_phys(struct iommu_domain *domain, { struct gart_device *gart = gart_handle; unsigned long pte; - phys_addr_t pa; - unsigned long flags; - if (!gart_iova_range_valid(gart, iova, 0)) + if (gart_iova_range_invalid(gart, iova, GART_PAGE_SIZE)) return -EINVAL; - spin_lock_irqsave(&gart->pte_lock, flags); + spin_lock(&gart->pte_lock); pte = gart_read_pte(gart, iova); - spin_unlock_irqrestore(&gart->pte_lock, flags); + spin_unlock(&gart->pte_lock); - pa = (pte & GART_PAGE_MASK); - if (!pfn_valid(__phys_to_pfn(pa))) { - dev_err(gart->dev, "No entry for %08llx:%pa\n", - (unsigned long long)iova, &pa); - gart_dump_table(gart); - return -EINVAL; - } - return pa; + return pte & GART_PAGE_MASK; } static bool gart_iommu_capable(enum iommu_cap cap) @@ -322,9 +287,7 @@ static int gart_iommu_of_xlate(struct device *dev, static void gart_iommu_sync(struct iommu_domain *domain) { - struct gart_device *gart = gart_handle; - - FLUSH_GART_REGS(gart); + FLUSH_GART_REGS(gart_handle); } static const struct iommu_ops gart_iommu_ops = { @@ -347,84 +310,78 @@ static const struct iommu_ops gart_iommu_ops = { int tegra_gart_suspend(struct gart_device *gart) { - unsigned long iova; u32 *data = gart->savedata; - unsigned long flags; + unsigned long iova; + + /* + * All GART users shall be suspended at this point. Disable + * address translation to trap all GART accesses as invalid + * memory accesses. + */ + writel_relaxed(0, gart->regs + GART_CONFIG); + FLUSH_GART_REGS(gart); - spin_lock_irqsave(&gart->pte_lock, flags); for_each_gart_pte(gart, iova) *(data++) = gart_read_pte(gart, iova); - spin_unlock_irqrestore(&gart->pte_lock, flags); + return 0; } int tegra_gart_resume(struct gart_device *gart) { - unsigned long flags; - - spin_lock_irqsave(&gart->pte_lock, flags); do_gart_setup(gart, gart->savedata); - spin_unlock_irqrestore(&gart->pte_lock, flags); + return 0; } struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc) { struct gart_device *gart; - struct resource *res_remap; - void __iomem *gart_regs; - int ret; + struct resource *res; + int err; BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT); /* the GART memory aperture is required */ - res_remap = platform_get_resource(to_platform_device(dev), - IORESOURCE_MEM, 1); - if (!res_remap) { - dev_err(dev, "GART memory aperture expected\n"); + res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 1); + if (!res) { + dev_err(dev, "Memory aperture resource unavailable\n"); return ERR_PTR(-ENXIO); } gart = kzalloc(sizeof(*gart), GFP_KERNEL); - if (!gart) { - dev_err(dev, "failed to allocate gart_device\n"); + if (!gart) return ERR_PTR(-ENOMEM); - } - ret = iommu_device_sysfs_add(&gart->iommu, dev, NULL, "gart"); - if (ret) { - dev_err(dev, "Failed to register IOMMU in sysfs\n"); + gart_handle = gart; + + gart->dev = dev; + gart->regs = mc->regs + GART_REG_BASE; + gart->iovmm_base = res->start; + gart->iovmm_end = res->end + 1; + spin_lock_init(&gart->pte_lock); + spin_lock_init(&gart->dom_lock); + + do_gart_setup(gart, NULL); + + err = iommu_device_sysfs_add(&gart->iommu, dev, NULL, "gart"); + if (err) goto free_gart; - } iommu_device_set_ops(&gart->iommu, &gart_iommu_ops); iommu_device_set_fwnode(&gart->iommu, dev->fwnode); - ret = iommu_device_register(&gart->iommu); - if (ret) { - dev_err(dev, "Failed to register IOMMU\n"); + err = iommu_device_register(&gart->iommu); + if (err) goto remove_sysfs; - } - gart->dev = dev; - gart_regs = mc->regs + GART_REG_BASE; - spin_lock_init(&gart->pte_lock); - spin_lock_init(&gart->dom_lock); - gart->regs = gart_regs; - gart->iovmm_base = (dma_addr_t)res_remap->start; - gart->page_count = (resource_size(res_remap) >> GART_PAGE_SHIFT); - - gart->savedata = vmalloc(array_size(sizeof(u32), gart->page_count)); + gart->savedata = vmalloc(resource_size(res) / GART_PAGE_SIZE * + sizeof(u32)); if (!gart->savedata) { - dev_err(dev, "failed to allocate context save area\n"); - ret = -ENOMEM; + err = -ENOMEM; goto unregister_iommu; } - do_gart_setup(gart, NULL); - - gart_handle = gart; - return gart; unregister_iommu: @@ -434,7 +391,7 @@ remove_sysfs: free_gart: kfree(gart); - return ERR_PTR(ret); + return ERR_PTR(err); } module_param(gart_debug, bool, 0644); -- cgit v1.2.3 From 51908d2e9b7c7730608a19f24fc8718af745bb2f Mon Sep 17 00:00:00 2001 From: Pascal PAILLET-LME Date: Mon, 14 Jan 2019 10:05:16 +0000 Subject: mfd: stpmic1: Add STPMIC1 driver STPMIC1 is a PMIC from STMicroelectronics. The STPMIC1 integrates 10 regulators, 3 power switches, a watchdog and an input for a power on key. Signed-off-by: Pascal Paillet Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 16 ++++ drivers/mfd/Makefile | 1 + drivers/mfd/stpmic1.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 drivers/mfd/stpmic1.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8c5dfdce4326..0761cb83d174 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1871,6 +1871,22 @@ config MFD_STM32_TIMERS for PWM and IIO Timer. This driver allow to share the registers between the others drivers. +config MFD_STPMIC1 + tristate "Support for STPMIC1 PMIC" + depends on (I2C=y && OF) + select REGMAP_I2C + select REGMAP_IRQ + select MFD_CORE + help + Support for ST Microelectronics STPMIC1 PMIC. STPMIC1 has power on + key, watchdog and regulator functionalities which are supported via + the relevant subsystems. This driver provides core support for the + STPMIC1. In order to use the actual functionaltiy of the device other + drivers must be enabled. + + To compile this driver as a module, choose M here: the + module will be called stpmic1. + menu "Multimedia Capabilities Port drivers" depends on ARCH_SA1100 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 12980a4ad460..a62fb0112d9f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -233,6 +233,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o +obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c new file mode 100644 index 000000000000..7dfbe8906cb8 --- /dev/null +++ b/drivers/mfd/stpmic1.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define STPMIC1_MAIN_IRQ 0 + +static const struct regmap_range stpmic1_readable_ranges[] = { + regmap_reg_range(TURN_ON_SR, VERSION_SR), + regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR), + regmap_reg_range(BST_SW_CR, BST_SW_CR), + regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4), + regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4), + regmap_reg_range(INT_MASK_R1, INT_MASK_R4), + regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4), + regmap_reg_range(INT_CLEAR_MASK_R1, INT_CLEAR_MASK_R4), + regmap_reg_range(INT_SRC_R1, INT_SRC_R1), +}; + +static const struct regmap_range stpmic1_writeable_ranges[] = { + regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR), + regmap_reg_range(BST_SW_CR, BST_SW_CR), + regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4), + regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4), + regmap_reg_range(INT_CLEAR_MASK_R1, INT_CLEAR_MASK_R4), +}; + +static const struct regmap_range stpmic1_volatile_ranges[] = { + regmap_reg_range(TURN_ON_SR, VERSION_SR), + regmap_reg_range(WCHDG_CR, WCHDG_CR), + regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4), + regmap_reg_range(INT_SRC_R1, INT_SRC_R4), +}; + +static const struct regmap_access_table stpmic1_readable_table = { + .yes_ranges = stpmic1_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(stpmic1_readable_ranges), +}; + +static const struct regmap_access_table stpmic1_writeable_table = { + .yes_ranges = stpmic1_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(stpmic1_writeable_ranges), +}; + +static const struct regmap_access_table stpmic1_volatile_table = { + .yes_ranges = stpmic1_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(stpmic1_volatile_ranges), +}; + +const struct regmap_config stpmic1_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = PMIC_MAX_REGISTER_ADDRESS, + .rd_table = &stpmic1_readable_table, + .wr_table = &stpmic1_writeable_table, + .volatile_table = &stpmic1_volatile_table, +}; + +static const struct regmap_irq stpmic1_irqs[] = { + REGMAP_IRQ_REG(IT_PONKEY_F, 0, 0x01), + REGMAP_IRQ_REG(IT_PONKEY_R, 0, 0x02), + REGMAP_IRQ_REG(IT_WAKEUP_F, 0, 0x04), + REGMAP_IRQ_REG(IT_WAKEUP_R, 0, 0x08), + REGMAP_IRQ_REG(IT_VBUS_OTG_F, 0, 0x10), + REGMAP_IRQ_REG(IT_VBUS_OTG_R, 0, 0x20), + REGMAP_IRQ_REG(IT_SWOUT_F, 0, 0x40), + REGMAP_IRQ_REG(IT_SWOUT_R, 0, 0x80), + + REGMAP_IRQ_REG(IT_CURLIM_BUCK1, 1, 0x01), + REGMAP_IRQ_REG(IT_CURLIM_BUCK2, 1, 0x02), + REGMAP_IRQ_REG(IT_CURLIM_BUCK3, 1, 0x04), + REGMAP_IRQ_REG(IT_CURLIM_BUCK4, 1, 0x08), + REGMAP_IRQ_REG(IT_OCP_OTG, 1, 0x10), + REGMAP_IRQ_REG(IT_OCP_SWOUT, 1, 0x20), + REGMAP_IRQ_REG(IT_OCP_BOOST, 1, 0x40), + REGMAP_IRQ_REG(IT_OVP_BOOST, 1, 0x80), + + REGMAP_IRQ_REG(IT_CURLIM_LDO1, 2, 0x01), + REGMAP_IRQ_REG(IT_CURLIM_LDO2, 2, 0x02), + REGMAP_IRQ_REG(IT_CURLIM_LDO3, 2, 0x04), + REGMAP_IRQ_REG(IT_CURLIM_LDO4, 2, 0x08), + REGMAP_IRQ_REG(IT_CURLIM_LDO5, 2, 0x10), + REGMAP_IRQ_REG(IT_CURLIM_LDO6, 2, 0x20), + REGMAP_IRQ_REG(IT_SHORT_SWOTG, 2, 0x40), + REGMAP_IRQ_REG(IT_SHORT_SWOUT, 2, 0x80), + + REGMAP_IRQ_REG(IT_TWARN_F, 3, 0x01), + REGMAP_IRQ_REG(IT_TWARN_R, 3, 0x02), + REGMAP_IRQ_REG(IT_VINLOW_F, 3, 0x04), + REGMAP_IRQ_REG(IT_VINLOW_R, 3, 0x08), + REGMAP_IRQ_REG(IT_SWIN_F, 3, 0x40), + REGMAP_IRQ_REG(IT_SWIN_R, 3, 0x80), +}; + +static const struct regmap_irq_chip stpmic1_regmap_irq_chip = { + .name = "pmic_irq", + .status_base = INT_PENDING_R1, + .mask_base = INT_CLEAR_MASK_R1, + .unmask_base = INT_SET_MASK_R1, + .ack_base = INT_CLEAR_R1, + .num_regs = STPMIC1_PMIC_NUM_IRQ_REGS, + .irqs = stpmic1_irqs, + .num_irqs = ARRAY_SIZE(stpmic1_irqs), +}; + +static int stpmic1_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct stpmic1 *ddata; + struct device *dev = &i2c->dev; + int ret; + struct device_node *np = dev->of_node; + u32 reg; + + ddata = devm_kzalloc(dev, sizeof(struct stpmic1), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + i2c_set_clientdata(i2c, ddata); + ddata->dev = dev; + + ddata->regmap = devm_regmap_init_i2c(i2c, &stpmic1_regmap_config); + if (IS_ERR(ddata->regmap)) + return PTR_ERR(ddata->regmap); + + ddata->irq = of_irq_get(np, STPMIC1_MAIN_IRQ); + if (ddata->irq < 0) { + dev_err(dev, "Failed to get main IRQ: %d\n", ddata->irq); + return ddata->irq; + } + + ret = regmap_read(ddata->regmap, VERSION_SR, ®); + if (ret) { + dev_err(dev, "Unable to read PMIC version\n"); + return ret; + } + dev_info(dev, "PMIC Chip Version: 0x%x\n", reg); + + /* Initialize PMIC IRQ Chip & associated IRQ domains */ + ret = devm_regmap_add_irq_chip(dev, ddata->regmap, ddata->irq, + IRQF_ONESHOT | IRQF_SHARED, + 0, &stpmic1_regmap_irq_chip, + &ddata->irq_data); + if (ret) { + dev_err(dev, "IRQ Chip registration failed: %d\n", ret); + return ret; + } + + return devm_of_platform_populate(dev); +} + +#ifdef CONFIG_PM_SLEEP +static int stpmic1_suspend(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c); + + disable_irq(pmic_dev->irq); + + return 0; +} + +static int stpmic1_resume(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c); + int ret; + + ret = regcache_sync(pmic_dev->regmap); + if (ret) + return ret; + + enable_irq(pmic_dev->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(stpmic1_pm, stpmic1_suspend, stpmic1_resume); + +static const struct of_device_id stpmic1_of_match[] = { + { .compatible = "st,stpmic1", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stpmic1_of_match); + +static struct i2c_driver stpmic1_driver = { + .driver = { + .name = "stpmic1", + .of_match_table = of_match_ptr(stpmic1_of_match), + .pm = &stpmic1_pm, + }, + .probe = stpmic1_probe, +}; + +module_i2c_driver(stpmic1_driver); + +MODULE_DESCRIPTION("STPMIC1 PMIC Driver"); +MODULE_AUTHOR("Pascal Paillet "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 9eb9cc932cfa43ac53d82b1b8d593a3a975be99e Mon Sep 17 00:00:00 2001 From: Pascal PAILLET-LME Date: Mon, 14 Jan 2019 10:05:17 +0000 Subject: input: stpmic1: Add STPMIC1 onkey driver The STPMIC1 pmic is able to manage an onkey button. This driver exposes the STPMIC1 onkey as an input device. It can also be configured to shut-down the power supplies on a long key-press with an adjustable duration. Signed-off-by: Pascal Paillet Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/misc/Kconfig | 11 +++ drivers/input/misc/Makefile | 2 + drivers/input/misc/stpmic1_onkey.c | 198 +++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 drivers/input/misc/stpmic1_onkey.c (limited to 'drivers') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ca59a2be9bc5..279fb02a0f14 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -851,4 +851,15 @@ config INPUT_SC27XX_VIBRA To compile this driver as a module, choose M here. The module will be called sc27xx_vibra. +config INPUT_STPMIC1_ONKEY + tristate "STPMIC1 PMIC Onkey support" + depends on MFD_STPMIC1 + help + Say Y to enable support of onkey embedded into STPMIC1 PMIC. onkey + can be used to wakeup from low power modes and force a shut-down on + long press. + + To compile this driver as a module, choose M here: the + module will be called stpmic1_onkey. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9d0f9d1ff68f..1b44202ad8f7 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o +obj-$(CONFIG_INPUT_STPMIC1_ONKEY) += stpmic1_onkey.o obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o @@ -81,3 +82,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o + diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c new file mode 100644 index 000000000000..7b49c9997df7 --- /dev/null +++ b/drivers/input/misc/stpmic1_onkey.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet for STMicroelectronics. + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct stpmic1_onkey - OnKey data + * @input_dev: pointer to input device + * @irq_falling: irq that we are hooked on to + * @irq_rising: irq that we are hooked on to + */ +struct stpmic1_onkey { + struct input_dev *input_dev; + int irq_falling; + int irq_rising; +}; + +static irqreturn_t onkey_falling_irq(int irq, void *ponkey) +{ + struct stpmic1_onkey *onkey = ponkey; + struct input_dev *input_dev = onkey->input_dev; + + input_report_key(input_dev, KEY_POWER, 1); + pm_wakeup_event(input_dev->dev.parent, 0); + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t onkey_rising_irq(int irq, void *ponkey) +{ + struct stpmic1_onkey *onkey = ponkey; + struct input_dev *input_dev = onkey->input_dev; + + input_report_key(input_dev, KEY_POWER, 0); + pm_wakeup_event(input_dev->dev.parent, 0); + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static int stpmic1_onkey_probe(struct platform_device *pdev) +{ + struct stpmic1 *pmic = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct input_dev *input_dev; + struct stpmic1_onkey *onkey; + unsigned int val, reg = 0; + int error; + + onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) + return -ENOMEM; + + onkey->irq_falling = platform_get_irq_byname(pdev, "onkey-falling"); + if (onkey->irq_falling < 0) { + dev_err(dev, "failed: request IRQ onkey-falling %d\n", + onkey->irq_falling); + return onkey->irq_falling; + } + + onkey->irq_rising = platform_get_irq_byname(pdev, "onkey-rising"); + if (onkey->irq_rising < 0) { + dev_err(dev, "failed: request IRQ onkey-rising %d\n", + onkey->irq_rising); + return onkey->irq_rising; + } + + if (!device_property_read_u32(dev, "power-off-time-sec", &val)) { + if (val > 0 && val <= 16) { + dev_dbg(dev, "power-off-time=%d seconds\n", val); + reg |= PONKEY_PWR_OFF; + reg |= ((16 - val) & PONKEY_TURNOFF_TIMER_MASK); + } else { + dev_err(dev, "power-off-time-sec out of range\n"); + return -EINVAL; + } + } + + if (device_property_present(dev, "st,onkey-clear-cc-flag")) + reg |= PONKEY_CC_FLAG_CLEAR; + + error = regmap_update_bits(pmic->regmap, PKEY_TURNOFF_CR, + PONKEY_TURNOFF_MASK, reg); + if (error) { + dev_err(dev, "PKEY_TURNOFF_CR write failed: %d\n", error); + return error; + } + + if (device_property_present(dev, "st,onkey-pu-inactive")) { + error = regmap_update_bits(pmic->regmap, PADS_PULL_CR, + PONKEY_PU_INACTIVE, + PONKEY_PU_INACTIVE); + if (error) { + dev_err(dev, "ONKEY Pads configuration failed: %d\n", + error); + return error; + } + } + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) { + dev_err(dev, "Can't allocate Pwr Onkey Input Device\n"); + return -ENOMEM; + } + + input_dev->name = "pmic_onkey"; + input_dev->phys = "pmic_onkey/input0"; + + input_set_capability(input_dev, EV_KEY, KEY_POWER); + + onkey->input_dev = input_dev; + + /* interrupt is nested in a thread */ + error = devm_request_threaded_irq(dev, onkey->irq_falling, NULL, + onkey_falling_irq, IRQF_ONESHOT, + dev_name(dev), onkey); + if (error) { + dev_err(dev, "Can't get IRQ Onkey Falling: %d\n", error); + return error; + } + + error = devm_request_threaded_irq(dev, onkey->irq_rising, NULL, + onkey_rising_irq, IRQF_ONESHOT, + dev_name(dev), onkey); + if (error) { + dev_err(dev, "Can't get IRQ Onkey Rising: %d\n", error); + return error; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(dev, "Can't register power button: %d\n", error); + return error; + } + + platform_set_drvdata(pdev, onkey); + device_init_wakeup(dev, true); + + return 0; +} + +static int __maybe_unused stpmic1_onkey_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) { + enable_irq_wake(onkey->irq_falling); + enable_irq_wake(onkey->irq_rising); + } + return 0; +} + +static int __maybe_unused stpmic1_onkey_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) { + disable_irq_wake(onkey->irq_falling); + disable_irq_wake(onkey->irq_rising); + } + return 0; +} + +static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm, + stpmic1_onkey_suspend, + stpmic1_onkey_resume); + +static const struct of_device_id of_stpmic1_onkey_match[] = { + { .compatible = "st,stpmic1-onkey" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, of_stpmic1_onkey_match); + +static struct platform_driver stpmic1_onkey_driver = { + .probe = stpmic1_onkey_probe, + .driver = { + .name = "stpmic1_onkey", + .of_match_table = of_match_ptr(of_stpmic1_onkey_match), + .pm = &stpmic1_onkey_pm, + }, +}; +module_platform_driver(stpmic1_onkey_driver); + +MODULE_DESCRIPTION("Onkey driver for STPMIC1"); +MODULE_AUTHOR("Pascal Paillet "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 28804c2c8fb3401aa4b7f16a883d49dd82f5e377 Mon Sep 17 00:00:00 2001 From: Pascal PAILLET-LME Date: Mon, 14 Jan 2019 10:05:18 +0000 Subject: watchdog: stpmic1: Add STPMIC1 watchdog driver The STPMIC1 PMIC embeds a watchdog which is disabled by default. As soon as the watchdog is started, it must be refreshed periodically otherwise the PMIC goes off. Signed-off-by: Pascal Paillet Reviewed-by: Guenter Roeck Signed-off-by: Lee Jones --- drivers/watchdog/Kconfig | 12 ++++ drivers/watchdog/Makefile | 1 + drivers/watchdog/stpmic1_wdt.c | 139 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 drivers/watchdog/stpmic1_wdt.c (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 57f017d74a97..65c3c42b5e7c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -817,6 +817,18 @@ config STM32_WATCHDOG To compile this driver as a module, choose M here: the module will be called stm32_iwdg. +config STPMIC1_WATCHDOG + tristate "STPMIC1 PMIC watchdog support" + depends on MFD_STPMIC1 + select WATCHDOG_CORE + help + Say Y here to include watchdog support embedded into STPMIC1 PMIC. + If the watchdog timer expires, stpmic1 will shut down all its power + supplies. + + To compile this driver as a module, choose M here: the + module will be called spmic1_wdt. + config UNIPHIER_WATCHDOG tristate "UniPhier watchdog support" depends on ARCH_UNIPHIER || COMPILE_TEST diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index a0917ef28e07..4e78a8c73f0c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -220,3 +220,4 @@ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o obj-$(CONFIG_MENZ069_WATCHDOG) += menz69_wdt.o obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o +obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c new file mode 100644 index 000000000000..ad431d8ad95f --- /dev/null +++ b/drivers/watchdog/stpmic1_wdt.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet for STMicroelectronics. + +#include +#include +#include +#include +#include +#include +#include +#include + +/* WATCHDOG CONTROL REGISTER bit */ +#define WDT_START BIT(0) +#define WDT_PING BIT(1) +#define WDT_START_MASK BIT(0) +#define WDT_PING_MASK BIT(1) +#define WDT_STOP 0 + +#define PMIC_WDT_MIN_TIMEOUT 1 +#define PMIC_WDT_MAX_TIMEOUT 256 +#define PMIC_WDT_DEFAULT_TIMEOUT 30 + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +struct stpmic1_wdt { + struct stpmic1 *pmic; + struct watchdog_device wdtdev; +}; + +static int pmic_wdt_start(struct watchdog_device *wdd) +{ + struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); + + return regmap_update_bits(wdt->pmic->regmap, + WCHDG_CR, WDT_START_MASK, WDT_START); +} + +static int pmic_wdt_stop(struct watchdog_device *wdd) +{ + struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); + + return regmap_update_bits(wdt->pmic->regmap, + WCHDG_CR, WDT_START_MASK, WDT_STOP); +} + +static int pmic_wdt_ping(struct watchdog_device *wdd) +{ + struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); + + return regmap_update_bits(wdt->pmic->regmap, + WCHDG_CR, WDT_PING_MASK, WDT_PING); +} + +static int pmic_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); + + wdd->timeout = timeout; + /* timeout is equal to register value + 1 */ + return regmap_write(wdt->pmic->regmap, WCHDG_TIMER_CR, timeout - 1); +} + +static const struct watchdog_info pmic_watchdog_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, + .identity = "STPMIC1 PMIC Watchdog", +}; + +static const struct watchdog_ops pmic_watchdog_ops = { + .owner = THIS_MODULE, + .start = pmic_wdt_start, + .stop = pmic_wdt_stop, + .ping = pmic_wdt_ping, + .set_timeout = pmic_wdt_set_timeout, +}; + +static int pmic_wdt_probe(struct platform_device *pdev) +{ + int ret; + struct stpmic1 *pmic; + struct stpmic1_wdt *wdt; + + if (!pdev->dev.parent) + return -EINVAL; + + pmic = dev_get_drvdata(pdev->dev.parent); + if (!pmic) + return -EINVAL; + + wdt = devm_kzalloc(&pdev->dev, sizeof(struct stpmic1_wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdt->pmic = pmic; + + wdt->wdtdev.info = &pmic_watchdog_info; + wdt->wdtdev.ops = &pmic_watchdog_ops; + wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT; + wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT; + wdt->wdtdev.parent = &pdev->dev; + + wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT; + watchdog_init_timeout(&wdt->wdtdev, 0, &pdev->dev); + + watchdog_set_nowayout(&wdt->wdtdev, nowayout); + watchdog_set_drvdata(&wdt->wdtdev, wdt); + + ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev); + if (ret) + return ret; + + dev_dbg(wdt->pmic->dev, "PMIC Watchdog driver probed\n"); + return 0; +} + +static const struct of_device_id of_pmic_wdt_match[] = { + { .compatible = "st,stpmic1-wdt" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, of_pmic_wdt_match); + +static struct platform_driver stpmic1_wdt_driver = { + .probe = pmic_wdt_probe, + .driver = { + .name = "stpmic1-wdt", + .of_match_table = of_pmic_wdt_match, + }, +}; +module_platform_driver(stpmic1_wdt_driver); + +MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device"); +MODULE_AUTHOR("Pascal Paillet "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 9cca9b3e55989f8b227d05897877648d67910a6d Mon Sep 17 00:00:00 2001 From: Guochun Mao Date: Wed, 16 Jan 2019 10:12:04 +0800 Subject: mtd: spi-nor: mtk-quadspi: add SNOR_HWCAPS_READ to spi_nor_hwcaps mask SNOR_HWCAPS_READ should be supported by this controller, so add this flag to spi_nor_hwcaps mask. Signed-off-by: Guochun Mao Signed-off-by: Ryder Lee Reviewed-by: Tudor Ambarus Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/mtk-quadspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c index 5442993b71ff..d9eed6844ba1 100644 --- a/drivers/mtd/spi-nor/mtk-quadspi.c +++ b/drivers/mtd/spi-nor/mtk-quadspi.c @@ -431,7 +431,8 @@ static int mtk_nor_init(struct mtk_nor *mtk_nor, struct device_node *flash_node) { const struct spi_nor_hwcaps hwcaps = { - .mask = SNOR_HWCAPS_READ_FAST | + .mask = SNOR_HWCAPS_READ | + SNOR_HWCAPS_READ_FAST | SNOR_HWCAPS_READ_1_1_2 | SNOR_HWCAPS_PP, }; -- cgit v1.2.3 From 356dd9ce2361ba5ba74eeff227fb6ab6d46e128c Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 16 Jan 2019 10:12:05 +0800 Subject: mtd: spi-nor: mtk-quadspi: rename config to a common one The quadspi is a generic communication interface which could be shared with other MediaTek SoCs. Hence rename it to a common one. Signed-off-by: Ryder Lee Reviewed-by: Tudor Ambarus Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/Kconfig | 16 ++++++++-------- drivers/mtd/spi-nor/Makefile | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 44fe8018733c..414e88749b1f 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -7,14 +7,6 @@ menuconfig MTD_SPI_NOR if MTD_SPI_NOR -config MTD_MT81xx_NOR - tristate "Mediatek MT81xx SPI NOR flash controller" - depends on HAS_IOMEM - help - This enables access to SPI NOR flash, using MT81xx SPI NOR flash - controller. This controller does not support generic SPI BUS, it only - supports SPI NOR Flash. - config MTD_SPI_NOR_USE_4K_SECTORS bool "Use small 4096 B erase sectors" default y @@ -66,6 +58,14 @@ config SPI_HISI_SFC help This enables support for hisilicon SPI-NOR flash controller. +config SPI_MTK_QUADSPI + tristate "MediaTek Quad SPI controller" + depends on HAS_IOMEM + help + This enables support for the Quad SPI controller in master mode. + This controller does not support generic SPI. It only supports + SPI NOR. + config SPI_NXP_SPIFI tristate "NXP SPI Flash Interface (SPIFI)" depends on OF && (ARCH_LPC18XX || COMPILE_TEST) diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index a552efd22958..4e4d4005d7a6 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o -obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o +obj-$(CONFIG_SPI_MTK_QUADSPI) += mtk-quadspi.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o -- cgit v1.2.3 From f8261c376e7f8cb9024af5a6c54be540c7f9108e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 14 Jan 2019 13:49:46 +0300 Subject: drm/etnaviv: NULL vs IS_ERR() buf in etnaviv_core_dump() The etnaviv_gem_get_pages() never returns NULL. It returns error pointers on error. Fixes: a8c21a5451d8 ("drm/etnaviv: add initial etnaviv DRM driver") Signed-off-by: Dan Carpenter Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index 3fbb4855396c..33854c94cb85 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -215,7 +215,7 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) mutex_lock(&obj->lock); pages = etnaviv_gem_get_pages(obj); mutex_unlock(&obj->lock); - if (pages) { + if (!IS_ERR(pages)) { int j; iter.hdr->data[0] = bomap - bomap_start; -- cgit v1.2.3 From c1d5fb019f65e1093c77734356f97b6e7ac4d629 Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Fri, 9 Nov 2018 14:03:26 -0500 Subject: media: usb: pwc: Introduce TRACE_EVENTs for pwc_isoc_handler() There were reports that PWC-based webcams don't work at some embedded ARM platforms. [1] Isochronous transfer handler seems to work too long leading to the issues in MUSB USB host subsystem. Also note, that urb->giveback() handlers are still called with disabled interrupts. In order to be able to measure performance of PWC driver, traces are introduced in URB handler section. [1] https://www.spinics.net/lists/linux-usb/msg165735.html Signed-off-by: Matwey V. Kornilov Reviewed-by: Steven Rostedt (VMware) Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pwc/pwc-if.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 72704f4d5330..53c111bd5a22 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -76,6 +76,9 @@ #include "pwc-dec23.h" #include "pwc-dec1.h" +#define CREATE_TRACE_POINTS +#include + /* Function prototypes and driver templates */ /* hotplug device table support */ @@ -260,6 +263,8 @@ static void pwc_isoc_handler(struct urb *urb) int i, fst, flen; unsigned char *iso_buf = NULL; + trace_pwc_handler_enter(urb, pdev); + if (urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN) { PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronously.\n", @@ -348,6 +353,8 @@ static void pwc_isoc_handler(struct urb *urb) } handler_end: + trace_pwc_handler_exit(urb, pdev); + i = usb_submit_urb(urb, GFP_ATOMIC); if (i != 0) PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); -- cgit v1.2.3 From 1161db6776bd1c35257e1e362e91bcb1b3fe4347 Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Fri, 9 Nov 2018 14:03:27 -0500 Subject: media: usb: pwc: Don't use coherent DMA buffers for ISO transfer DMA cocherency slows the transfer down on systems without hardware coherent DMA. Instead we use noncocherent DMA memory and explicit sync at data receive handler. Based on previous commit the following performance benchmarks have been carried out. Average memcpy() data transfer rate (rate) and handler completion time (time) have been measured when running video stream at 640x480 resolution at 10fps. x86_64 based system (Intel Core i5-3470). This platform has hardware coherent DMA support and proposed change doesn't make big difference here. * kmalloc: rate = (2.0 +- 0.4) GBps time = (5.0 +- 3.0) usec * usb_alloc_coherent: rate = (3.4 +- 1.2) GBps time = (3.5 +- 3.0) usec We see that the measurements agree within error ranges in this case. So theoretically predicted performance downgrade cannot be reliably measured here. armv7l based system (TI AM335x BeagleBone Black @ 300MHz). This platform has no hardware coherent DMA support. DMA coherence is implemented via disabled page caching that slows down memcpy() due to memory controller behaviour. * kmalloc: rate = ( 94 +- 4) MBps time = (101 +- 4) usec * usb_alloc_coherent: rate = (28.1 +- 0.1) MBps time = (341 +- 2) usec Note, that quantative difference leads (this commit leads to 3.3 times acceleration) to qualitative behavior change in this case. As it was stated before, the video stream cannot be successfully received at AM335x platforms with MUSB based USB host controller due to performance issues [1]. [1] https://www.spinics.net/lists/linux-usb/msg165735.html Signed-off-by: Matwey V. Kornilov Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pwc/pwc-if.c | 62 +++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 53c111bd5a22..a81fb319b339 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -159,6 +159,32 @@ static const struct video_device pwc_template = { /***************************************************************************/ /* Private functions */ +static void *pwc_alloc_urb_buffer(struct device *dev, + size_t size, dma_addr_t *dma_handle) +{ + void *buffer = kmalloc(size, GFP_KERNEL); + + if (!buffer) + return NULL; + + *dma_handle = dma_map_single(dev, buffer, size, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, *dma_handle)) { + kfree(buffer); + return NULL; + } + + return buffer; +} + +static void pwc_free_urb_buffer(struct device *dev, + size_t size, + void *buffer, + dma_addr_t dma_handle) +{ + dma_unmap_single(dev, dma_handle, size, DMA_FROM_DEVICE); + kfree(buffer); +} + static struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev) { unsigned long flags = 0; @@ -306,6 +332,11 @@ static void pwc_isoc_handler(struct urb *urb) /* Reset ISOC error counter. We did get here, after all. */ pdev->visoc_errors = 0; + dma_sync_single_for_cpu(&urb->dev->dev, + urb->transfer_dma, + urb->transfer_buffer_length, + DMA_FROM_DEVICE); + /* vsync: 0 = don't copy data 1 = sync-hunt 2 = synched @@ -352,6 +383,11 @@ static void pwc_isoc_handler(struct urb *urb) pdev->vlast_packet_size = flen; } + dma_sync_single_for_device(&urb->dev->dev, + urb->transfer_dma, + urb->transfer_buffer_length, + DMA_FROM_DEVICE); + handler_end: trace_pwc_handler_exit(urb, pdev); @@ -428,16 +464,15 @@ retry: urb->dev = udev; urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->transfer_buffer = usb_alloc_coherent(udev, - ISO_BUFFER_SIZE, - GFP_KERNEL, - &urb->transfer_dma); + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->transfer_buffer = pwc_alloc_urb_buffer(&udev->dev, + urb->transfer_buffer_length, + &urb->transfer_dma); if (urb->transfer_buffer == NULL) { PWC_ERROR("Failed to allocate urb buffer %d\n", i); pwc_isoc_cleanup(pdev); return -ENOMEM; } - urb->transfer_buffer_length = ISO_BUFFER_SIZE; urb->complete = pwc_isoc_handler; urb->context = pdev; urb->start_frame = 0; @@ -488,15 +523,16 @@ static void pwc_iso_free(struct pwc_device *pdev) /* Freeing ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { - if (pdev->urbs[i]) { + struct urb *urb = pdev->urbs[i]; + + if (urb) { PWC_DEBUG_MEMORY("Freeing URB\n"); - if (pdev->urbs[i]->transfer_buffer) { - usb_free_coherent(pdev->udev, - pdev->urbs[i]->transfer_buffer_length, - pdev->urbs[i]->transfer_buffer, - pdev->urbs[i]->transfer_dma); - } - usb_free_urb(pdev->urbs[i]); + if (urb->transfer_buffer) + pwc_free_urb_buffer(&urb->dev->dev, + urb->transfer_buffer_length, + urb->transfer_buffer, + urb->transfer_dma); + usb_free_urb(urb); pdev->urbs[i] = NULL; } } -- cgit v1.2.3 From 6c67fa07a3b43dd83158e55584addae00d38a514 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Fri, 7 Dec 2018 11:31:34 -0500 Subject: media: vsp1: Fix trivial documentation In the partition sizing the term 'prevents' is inappropriately pluralized. Simplify to 'prevent'. Signed-off-by: Kieran Bingham Reviewed-by: Simon Horman Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 771dfe1f7c20..7ceaf3222145 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -223,7 +223,7 @@ static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe, * If the modulus is less than half of the partition size, * the penultimate partition is reduced to half, which is added * to the final partition: |1234|1234|1234|12|341| - * to prevents this: |1234|1234|1234|1234|1|. + * to prevent this: |1234|1234|1234|1234|1|. */ if (modulus) { /* -- cgit v1.2.3 From aa8a1012ba624e92fd1ab58463f22501bce78af8 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 10 Dec 2018 09:53:55 -0500 Subject: media: rcar-csi2: Fix PHTW table values for E3/V3M MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PHTW selection algorithm implemented in rcsi2_phtw_write_mbps() checks for lower bound of the interval used to match the desired bandwidth. Use that in place of the currently used upper bound. Fixes: 10c08812fe60 ("media: rcar: rcar-csi2: Update V3M/E3 PHTW tables") Signed-off-by: Jacopo Mondi Acked-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 62 ++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 6d356f5a9456..b2bd0b9627d9 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -152,37 +152,37 @@ static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { }; static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { - { .mbps = 89, .reg = 0x00 }, - { .mbps = 99, .reg = 0x20 }, - { .mbps = 109, .reg = 0x40 }, - { .mbps = 129, .reg = 0x02 }, - { .mbps = 139, .reg = 0x22 }, - { .mbps = 149, .reg = 0x42 }, - { .mbps = 169, .reg = 0x04 }, - { .mbps = 179, .reg = 0x24 }, - { .mbps = 199, .reg = 0x44 }, - { .mbps = 219, .reg = 0x06 }, - { .mbps = 239, .reg = 0x26 }, - { .mbps = 249, .reg = 0x46 }, - { .mbps = 269, .reg = 0x08 }, - { .mbps = 299, .reg = 0x28 }, - { .mbps = 329, .reg = 0x0a }, - { .mbps = 359, .reg = 0x2a }, - { .mbps = 399, .reg = 0x4a }, - { .mbps = 449, .reg = 0x0c }, - { .mbps = 499, .reg = 0x2c }, - { .mbps = 549, .reg = 0x0e }, - { .mbps = 599, .reg = 0x2e }, - { .mbps = 649, .reg = 0x10 }, - { .mbps = 699, .reg = 0x30 }, - { .mbps = 749, .reg = 0x12 }, - { .mbps = 799, .reg = 0x32 }, - { .mbps = 849, .reg = 0x52 }, - { .mbps = 899, .reg = 0x72 }, - { .mbps = 949, .reg = 0x14 }, - { .mbps = 999, .reg = 0x34 }, - { .mbps = 1049, .reg = 0x54 }, - { .mbps = 1099, .reg = 0x74 }, + { .mbps = 80, .reg = 0x00 }, + { .mbps = 90, .reg = 0x20 }, + { .mbps = 100, .reg = 0x40 }, + { .mbps = 110, .reg = 0x02 }, + { .mbps = 130, .reg = 0x22 }, + { .mbps = 140, .reg = 0x42 }, + { .mbps = 150, .reg = 0x04 }, + { .mbps = 170, .reg = 0x24 }, + { .mbps = 180, .reg = 0x44 }, + { .mbps = 200, .reg = 0x06 }, + { .mbps = 220, .reg = 0x26 }, + { .mbps = 240, .reg = 0x46 }, + { .mbps = 250, .reg = 0x08 }, + { .mbps = 270, .reg = 0x28 }, + { .mbps = 300, .reg = 0x0a }, + { .mbps = 330, .reg = 0x2a }, + { .mbps = 360, .reg = 0x4a }, + { .mbps = 400, .reg = 0x0c }, + { .mbps = 450, .reg = 0x2c }, + { .mbps = 500, .reg = 0x0e }, + { .mbps = 550, .reg = 0x2e }, + { .mbps = 600, .reg = 0x10 }, + { .mbps = 650, .reg = 0x30 }, + { .mbps = 700, .reg = 0x12 }, + { .mbps = 750, .reg = 0x32 }, + { .mbps = 800, .reg = 0x52 }, + { .mbps = 850, .reg = 0x72 }, + { .mbps = 900, .reg = 0x14 }, + { .mbps = 950, .reg = 0x34 }, + { .mbps = 1000, .reg = 0x54 }, + { .mbps = 1050, .reg = 0x74 }, { .mbps = 1125, .reg = 0x16 }, { /* sentinel */ }, }; -- cgit v1.2.3 From 66e988e96b31d0c06471234cabb0a77316841fc3 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 13 Dec 2018 08:31:07 -0500 Subject: media: Change Andrzej Pietrasiewicz's e-mail address My @samsung.com address is going to cease existing soon, so change it to an address which can actually be used to contact me. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 2 +- drivers/media/platform/s5p-jpeg/jpeg-core.c | 4 ++-- drivers/media/platform/s5p-jpeg/jpeg-core.h | 2 +- drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c | 2 +- drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h | 2 +- drivers/media/platform/s5p-jpeg/jpeg-regs.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 015e737095cd..f02876d971d7 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -3,7 +3,7 @@ * * Copyright (C) 2010 Samsung Electronics * - * Author: Andrzej Pietrasiewicz + * Author: Andrzej Pietrasiewicz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 3f9000b70385..580d6d02557b 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -3,7 +3,7 @@ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz + * Author: Andrzej Pietrasiewicz * Author: Jacek Anaszewski * * This program is free software; you can redistribute it and/or modify @@ -3220,7 +3220,7 @@ static struct platform_driver s5p_jpeg_driver = { module_platform_driver(s5p_jpeg_driver); -MODULE_AUTHOR("Andrzej Pietrasiewicz "); +MODULE_AUTHOR("Andrzej Pietrasiewicz "); MODULE_AUTHOR("Jacek Anaszewski "); MODULE_DESCRIPTION("Samsung JPEG codec driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index a46465e10351..90fda4b720eb 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -3,7 +3,7 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz + * Author: Andrzej Pietrasiewicz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index b5f20e722b63..59c6263a71bf 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c @@ -3,7 +3,7 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz + * Author: Andrzej Pietrasiewicz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h index f208fa3ed738..bfe746f8f750 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h @@ -3,7 +3,7 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz + * Author: Andrzej Pietrasiewicz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h index df790b10140c..574f0e8021e5 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h @@ -5,7 +5,7 @@ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz + * Author: Andrzej Pietrasiewicz * Author: Jacek Anaszewski * * This program is free software; you can redistribute it and/or modify -- cgit v1.2.3 From 2a850b94135db67d87f4ab6ab2a325a42ecbe00a Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Mon, 17 Dec 2018 12:56:17 -0500 Subject: media: vicodec: bugfix - replace '=' with '|=' In the fwht_encode_frame, 'encoding = encode_plane' should be replaced with 'encoding |= encode_plane' so existing flags won't be overwrriten. Signed-off-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/codec-fwht.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vicodec/codec-fwht.c b/drivers/media/platform/vicodec/codec-fwht.c index 5630f1dc45e6..a6fd0477633b 100644 --- a/drivers/media/platform/vicodec/codec-fwht.c +++ b/drivers/media/platform/vicodec/codec-fwht.c @@ -787,10 +787,10 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, if (frm->components_num == 4) { rlco_max = rlco + size / 2 - 256; - encoding = encode_plane(frm->alpha, ref_frm->alpha, &rlco, - rlco_max, cf, frm->height, frm->width, - frm->luma_alpha_step, - is_intra, next_is_intra); + encoding |= encode_plane(frm->alpha, ref_frm->alpha, &rlco, + rlco_max, cf, frm->height, frm->width, + frm->luma_alpha_step, + is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) encoding |= FWHT_ALPHA_UNENCODED; encoding &= ~FWHT_FRAME_UNENCODED; -- cgit v1.2.3 From f45f3f753b0a3d739acda8e311b4f744d82dc52a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 18 Dec 2018 08:37:08 -0500 Subject: media: v4l2-ctrls.c/uvc: zero v4l2_event Control events can leak kernel memory since they do not fully zero the event. The same code is present in both v4l2-ctrls.c and uvc_ctrl.c, so fix both. It appears that all other event code is properly zeroing the structure, it's these two places. Signed-off-by: Hans Verkuil Reported-by: syzbot+4f021cf3697781dbd9fb@syzkaller.appspotmail.com Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 2 +- drivers/media/v4l2-core/v4l2-ctrls.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index d45415cbe6e7..14cff91b7aea 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1212,7 +1212,7 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain, __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl); - memset(ev->reserved, 0, sizeof(ev->reserved)); + memset(ev, 0, sizeof(*ev)); ev->type = V4L2_EVENT_CTRL; ev->id = v4l2_ctrl.id; ev->u.ctrl.value = value; diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index e3bd441fa29a..8c47d8f00429 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1387,7 +1387,7 @@ static u32 user_flags(const struct v4l2_ctrl *ctrl) static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes) { - memset(ev->reserved, 0, sizeof(ev->reserved)); + memset(ev, 0, sizeof(*ev)); ev->type = V4L2_EVENT_CTRL; ev->id = ctrl->id; ev->u.ctrl.changes = changes; -- cgit v1.2.3 From 6f2c6afa79e0513d339871337bfc8c6c621d3ab1 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Fri, 21 Dec 2018 11:56:41 -0500 Subject: media: sunxi: cedrus: Fix missing error message context When cedrus_hw_probe is called, v4l2_dev is not yet initialized. Use dev_err instead. Signed-off-by: Ondrej Jirman Acked-by: Paul Kocialkowski Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus_hw.c | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index 300339fee1bc..0acf219a8c91 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -157,14 +157,14 @@ int cedrus_hw_probe(struct cedrus_dev *dev) irq_dec = platform_get_irq(dev->pdev, 0); if (irq_dec <= 0) { - v4l2_err(&dev->v4l2_dev, "Failed to get IRQ\n"); + dev_err(dev->dev, "Failed to get IRQ\n"); return irq_dec; } ret = devm_request_irq(dev->dev, irq_dec, cedrus_irq, 0, dev_name(dev->dev), dev); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to request IRQ\n"); + dev_err(dev->dev, "Failed to request IRQ\n"); return ret; } @@ -182,21 +182,21 @@ int cedrus_hw_probe(struct cedrus_dev *dev) ret = of_reserved_mem_device_init(dev->dev); if (ret && ret != -ENODEV) { - v4l2_err(&dev->v4l2_dev, "Failed to reserve memory\n"); + dev_err(dev->dev, "Failed to reserve memory\n"); return ret; } ret = sunxi_sram_claim(dev->dev); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to claim SRAM\n"); + dev_err(dev->dev, "Failed to claim SRAM\n"); goto err_mem; } dev->ahb_clk = devm_clk_get(dev->dev, "ahb"); if (IS_ERR(dev->ahb_clk)) { - v4l2_err(&dev->v4l2_dev, "Failed to get AHB clock\n"); + dev_err(dev->dev, "Failed to get AHB clock\n"); ret = PTR_ERR(dev->ahb_clk); goto err_sram; @@ -204,7 +204,7 @@ int cedrus_hw_probe(struct cedrus_dev *dev) dev->mod_clk = devm_clk_get(dev->dev, "mod"); if (IS_ERR(dev->mod_clk)) { - v4l2_err(&dev->v4l2_dev, "Failed to get MOD clock\n"); + dev_err(dev->dev, "Failed to get MOD clock\n"); ret = PTR_ERR(dev->mod_clk); goto err_sram; @@ -212,7 +212,7 @@ int cedrus_hw_probe(struct cedrus_dev *dev) dev->ram_clk = devm_clk_get(dev->dev, "ram"); if (IS_ERR(dev->ram_clk)) { - v4l2_err(&dev->v4l2_dev, "Failed to get RAM clock\n"); + dev_err(dev->dev, "Failed to get RAM clock\n"); ret = PTR_ERR(dev->ram_clk); goto err_sram; @@ -220,7 +220,7 @@ int cedrus_hw_probe(struct cedrus_dev *dev) dev->rstc = devm_reset_control_get(dev->dev, NULL); if (IS_ERR(dev->rstc)) { - v4l2_err(&dev->v4l2_dev, "Failed to get reset control\n"); + dev_err(dev->dev, "Failed to get reset control\n"); ret = PTR_ERR(dev->rstc); goto err_sram; @@ -229,7 +229,7 @@ int cedrus_hw_probe(struct cedrus_dev *dev) res = platform_get_resource(dev->pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(dev->dev, res); if (IS_ERR(dev->base)) { - v4l2_err(&dev->v4l2_dev, "Failed to map registers\n"); + dev_err(dev->dev, "Failed to map registers\n"); ret = PTR_ERR(dev->base); goto err_sram; @@ -237,35 +237,35 @@ int cedrus_hw_probe(struct cedrus_dev *dev) ret = clk_set_rate(dev->mod_clk, CEDRUS_CLOCK_RATE_DEFAULT); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to set clock rate\n"); + dev_err(dev->dev, "Failed to set clock rate\n"); goto err_sram; } ret = clk_prepare_enable(dev->ahb_clk); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to enable AHB clock\n"); + dev_err(dev->dev, "Failed to enable AHB clock\n"); goto err_sram; } ret = clk_prepare_enable(dev->mod_clk); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to enable MOD clock\n"); + dev_err(dev->dev, "Failed to enable MOD clock\n"); goto err_ahb_clk; } ret = clk_prepare_enable(dev->ram_clk); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to enable RAM clock\n"); + dev_err(dev->dev, "Failed to enable RAM clock\n"); goto err_mod_clk; } ret = reset_control_reset(dev->rstc); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to apply reset\n"); + dev_err(dev->dev, "Failed to apply reset\n"); goto err_ram_clk; } -- cgit v1.2.3 From 5ceaf5452c1b2a452dadaf377f9f07af7bda9cc3 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Tue, 25 Dec 2018 01:31:21 -0500 Subject: media: usb: gspca: add a missed return-value check for do_command do_command() may fail. The fix adds the missed return value of do_command(). If it fails, returns its error code. Signed-off-by: Kangjie Lu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/cpia1.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index 2b09af8865f4..23fbda56fc91 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -547,10 +547,14 @@ static int do_command(struct gspca_dev *gspca_dev, u16 command, } if (sd->params.qx3.button) { /* button pressed - unlock the latch */ - do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, + ret = do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 3, 0xdf, 0xdf, 0); - do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, + if (ret) + return ret; + ret = do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 3, 0xff, 0xff, 0); + if (ret) + return ret; } /* test whether microscope is cradled */ -- cgit v1.2.3 From 5b711870bec4dc9a6d705d41e127e73944fa3650 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Tue, 25 Dec 2018 03:24:41 -0500 Subject: media: usb: gspca: add a missed check for goto_low_power The fix checks if goto_low_power() fails, and if so, issues an error message. Signed-off-by: Kangjie Lu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/cpia1.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index 23fbda56fc91..7c817a4a93c4 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -1434,6 +1434,7 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; + int ret; sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ; reset_camera_params(gspca_dev); @@ -1445,7 +1446,10 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = mode; cam->nmodes = ARRAY_SIZE(mode); - goto_low_power(gspca_dev); + ret = goto_low_power(gspca_dev); + if (ret) + gspca_err(gspca_dev, "Cannot go to low power mode: %d\n", + ret); /* Check the firmware version. */ sd->params.version.firmwareVersion = 0; get_version_information(gspca_dev); -- cgit v1.2.3 From a21a0eb56b4e8fe4a330243af8030f890cde2283 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Fri, 28 Dec 2018 13:37:36 -0500 Subject: media: gspca: Check the return value of write_bridge for timeout In po1030_probe(), m5602_write_bridge() can timeout and return an error value. The fix checks for the return value and propagates upstream consistent with other usb drivers. Signed-off-by: Aditya Pakki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/m5602/m5602_po1030.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c index 37d2891e5f5b..5e43b4782f02 100644 --- a/drivers/media/usb/gspca/m5602/m5602_po1030.c +++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c @@ -158,6 +158,7 @@ static const struct v4l2_ctrl_config po1030_greenbal_cfg = { int po1030_probe(struct sd *sd) { + int rc = 0; u8 dev_id_h = 0, i; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; @@ -177,11 +178,14 @@ int po1030_probe(struct sd *sd) for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { u8 data = preinit_po1030[i][2]; if (preinit_po1030[i][0] == SENSOR) - m5602_write_sensor(sd, + rc |= m5602_write_sensor(sd, preinit_po1030[i][1], &data, 1); else - m5602_write_bridge(sd, preinit_po1030[i][1], data); + rc |= m5602_write_bridge(sd, preinit_po1030[i][1], + data); } + if (rc < 0) + return rc; if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1)) return -ENODEV; -- cgit v1.2.3 From 656025850074f5c1ba2e05be37bda57ba2b8d491 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Fri, 28 Dec 2018 13:51:10 -0500 Subject: media: gspca: mt9m111: Check write_bridge for timeout In mt9m111_probe, m5602_write_bridge can timeout and return a negative error value. The fix checks for this error and passes it upstream. Signed-off-by: Aditya Pakki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/m5602/m5602_mt9m111.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c index c9947c4a0f63..8fac814f4779 100644 --- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c @@ -199,7 +199,7 @@ static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = { int mt9m111_probe(struct sd *sd) { u8 data[2] = {0x00, 0x00}; - int i; + int i, rc = 0; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { @@ -217,16 +217,18 @@ int mt9m111_probe(struct sd *sd) /* Do the preinit */ for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { if (preinit_mt9m111[i][0] == BRIDGE) { - m5602_write_bridge(sd, + rc |= m5602_write_bridge(sd, preinit_mt9m111[i][1], preinit_mt9m111[i][2]); } else { data[0] = preinit_mt9m111[i][2]; data[1] = preinit_mt9m111[i][3]; - m5602_write_sensor(sd, + rc |= m5602_write_sensor(sd, preinit_mt9m111[i][1], data, 2); } } + if (rc < 0) + return rc; if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) return -ENODEV; -- cgit v1.2.3 From 49710c32cd9d6626a77c9f5f978a5f58cb536b35 Mon Sep 17 00:00:00 2001 From: Pawe? Chmiel Date: Sat, 29 Dec 2018 10:46:01 -0500 Subject: media: s5p-jpeg: Check for fmt_ver_flag when doing fmt enumeration Previously when doing format enumeration, it was returning all formats supported by driver, even if they're not supported by hw. Add missing check for fmt_ver_flag, so it'll be fixed and only those supported by hw will be returned. Similar thing is already done in s5p_jpeg_find_format. It was found by using v4l2-compliance tool and checking result of VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS test and using v4l2-ctl to get list of all supported formats. Tested on s5pv210-galaxys (Samsung i9000 phone). Fixes: bb677f3ac434 ("[media] Exynos4 JPEG codec v4l2 driver") Signed-off-by: Pawe? Chmiel Reviewed-by: Jacek Anaszewski [hverkuil-cisco@xs4all.nl: fix a few alignment issues] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 580d6d02557b..85110766043f 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1293,13 +1293,16 @@ static int s5p_jpeg_querycap(struct file *file, void *priv, return 0; } -static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n, +static int enum_fmt(struct s5p_jpeg_ctx *ctx, + struct s5p_jpeg_fmt *sjpeg_formats, int n, struct v4l2_fmtdesc *f, u32 type) { int i, num = 0; + unsigned int fmt_ver_flag = ctx->jpeg->variant->fmt_ver_flag; for (i = 0; i < n; ++i) { - if (sjpeg_formats[i].flags & type) { + if (sjpeg_formats[i].flags & type && + sjpeg_formats[i].flags & fmt_ver_flag) { /* index-th format of type type found ? */ if (num == f->index) break; @@ -1326,11 +1329,11 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); if (ctx->mode == S5P_JPEG_ENCODE) - return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, + return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, SJPEG_FMT_FLAG_ENC_CAPTURE); - return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, - SJPEG_FMT_FLAG_DEC_CAPTURE); + return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, + SJPEG_FMT_FLAG_DEC_CAPTURE); } static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, @@ -1339,11 +1342,11 @@ static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); if (ctx->mode == S5P_JPEG_ENCODE) - return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, + return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, SJPEG_FMT_FLAG_ENC_OUTPUT); - return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, - SJPEG_FMT_FLAG_DEC_OUTPUT); + return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, + SJPEG_FMT_FLAG_DEC_OUTPUT); } static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx, -- cgit v1.2.3 From d6b10dd0017641fee31daa84e478708a33d2f00a Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sun, 30 Dec 2018 06:41:40 -0500 Subject: media: tw9910: fix failure handling in tw9910_power_on() If gpiod_get_optional() fails in tw9910_power_on(), clk is left undisabled. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index a54548cc4285..0971f8a34afb 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -610,6 +610,11 @@ static int tw9910_power_on(struct tw9910_priv *priv) GPIOD_OUT_LOW); if (IS_ERR(priv->rstb_gpio)) { dev_info(&client->dev, "Unable to get GPIO \"rstb\""); + clk_disable_unprepare(priv->clk); + if (priv->pdn_gpio) { + gpiod_set_value(priv->pdn_gpio, 1); + usleep_range(500, 1000); + } return PTR_ERR(priv->rstb_gpio); } -- cgit v1.2.3 From cf6a9896622da6233f8b25beeabb4a98729a49c3 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sun, 30 Dec 2018 06:41:41 -0500 Subject: media: tw9910: add helper function for setting gpiod value tw9910 driver tries to sleep for the same period of time after each gpiod_set_value(). The patch moves duplicated code to a helper function. Signed-off-by: Alexey Khoroshilov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 0971f8a34afb..8d1138e13803 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -584,6 +584,14 @@ static int tw9910_s_register(struct v4l2_subdev *sd, } #endif +static void tw9910_set_gpio_value(struct gpio_desc *desc, int value) +{ + if (desc) { + gpiod_set_value(desc, value); + usleep_range(500, 1000); + } +} + static int tw9910_power_on(struct tw9910_priv *priv) { struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); @@ -595,10 +603,7 @@ static int tw9910_power_on(struct tw9910_priv *priv) return ret; } - if (priv->pdn_gpio) { - gpiod_set_value(priv->pdn_gpio, 0); - usleep_range(500, 1000); - } + tw9910_set_gpio_value(priv->pdn_gpio, 0); /* * FIXME: The reset signal is connected to a shared GPIO on some @@ -611,18 +616,13 @@ static int tw9910_power_on(struct tw9910_priv *priv) if (IS_ERR(priv->rstb_gpio)) { dev_info(&client->dev, "Unable to get GPIO \"rstb\""); clk_disable_unprepare(priv->clk); - if (priv->pdn_gpio) { - gpiod_set_value(priv->pdn_gpio, 1); - usleep_range(500, 1000); - } + tw9910_set_gpio_value(priv->pdn_gpio, 1); return PTR_ERR(priv->rstb_gpio); } if (priv->rstb_gpio) { - gpiod_set_value(priv->rstb_gpio, 1); - usleep_range(500, 1000); - gpiod_set_value(priv->rstb_gpio, 0); - usleep_range(500, 1000); + tw9910_set_gpio_value(priv->rstb_gpio, 1); + tw9910_set_gpio_value(priv->rstb_gpio, 0); gpiod_put(priv->rstb_gpio); } @@ -633,11 +633,7 @@ static int tw9910_power_on(struct tw9910_priv *priv) static int tw9910_power_off(struct tw9910_priv *priv) { clk_disable_unprepare(priv->clk); - - if (priv->pdn_gpio) { - gpiod_set_value(priv->pdn_gpio, 1); - usleep_range(500, 1000); - } + tw9910_set_gpio_value(priv->pdn_gpio, 1); return 0; } -- cgit v1.2.3 From a86f2b590aa0259b961ffc39852e7c88f6c7e468 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 30 Dec 2018 08:20:16 -0500 Subject: media: staging: bcm2835-camera: use V4L2_FRACT_COMPARE Now the equivalent of FRACT_CMP() is added in v4l2 common internal API header. Signed-off-by: Akinobu Mita Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index 611a6ee2943a..7c6cf41645eb 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -1370,10 +1370,6 @@ static int vidioc_g_parm(struct file *file, void *priv, return 0; } -#define FRACT_CMP(a, OP, b) \ - ((u64)(a).numerator * (b).denominator OP \ - (u64)(b).numerator * (a).denominator) - static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { @@ -1387,8 +1383,8 @@ static int vidioc_s_parm(struct file *file, void *priv, /* tpf: {*, 0} resets timing; clip to [min, max]*/ tpf = tpf.denominator ? tpf : tpf_default; - tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf; - tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf; + tpf = V4L2_FRACT_COMPARE(tpf, <, tpf_min) ? tpf_min : tpf; + tpf = V4L2_FRACT_COMPARE(tpf, >, tpf_max) ? tpf_max : tpf; dev->capture.timeperframe = tpf; parm->parm.capture.timeperframe = tpf; -- cgit v1.2.3 From 6458afc8c49148f0a5015d8853039a0b3fb91d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Fri, 4 Jan 2019 11:12:18 -0500 Subject: media: rcar-vin: remove unneeded locking in async callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The locking implemented in the async notifier callbacks are unnecessary as the global list_lock in v4l2-async.c is held whenever one of the callbacks are called. The locking in itself is not harmful however it produces a LOCKDEP warning between the global v4l2-async list_lock and the rcar-vin local locking schema. Remove the rcar-vin locking for the async callbacks to reduce complexity and silent the false LOCKDEP warning. Signed-off-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index f0719ce24b97..0e81b557f3b6 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -542,9 +542,7 @@ static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name); - mutex_lock(&vin->lock); rvin_parallel_subdevice_detach(vin); - mutex_unlock(&vin->lock); } static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, @@ -554,9 +552,7 @@ static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); int ret; - mutex_lock(&vin->lock); ret = rvin_parallel_subdevice_attach(vin, subdev); - mutex_unlock(&vin->lock); if (ret) return ret; @@ -664,7 +660,6 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) } /* Create all media device links between VINs and CSI-2's. */ - mutex_lock(&vin->group->lock); for (route = vin->info->routes; route->mask; route++) { struct media_pad *source_pad, *sink_pad; struct media_entity *source, *sink; @@ -700,7 +695,6 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) break; } } - mutex_unlock(&vin->group->lock); return ret; } @@ -716,8 +710,6 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, if (vin->group->vin[i]) rvin_v4l2_unregister(vin->group->vin[i]); - mutex_lock(&vin->group->lock); - for (i = 0; i < RVIN_CSI_MAX; i++) { if (vin->group->csi[i].fwnode != asd->match.fwnode) continue; @@ -725,8 +717,6 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i); break; } - - mutex_unlock(&vin->group->lock); } static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, @@ -736,8 +726,6 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); unsigned int i; - mutex_lock(&vin->group->lock); - for (i = 0; i < RVIN_CSI_MAX; i++) { if (vin->group->csi[i].fwnode != asd->match.fwnode) continue; @@ -746,8 +734,6 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, break; } - mutex_unlock(&vin->group->lock); - return 0; } -- cgit v1.2.3 From f27dd0ad68850fdb806536a733a32d8f74810f1e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 10 Dec 2018 15:41:40 -0500 Subject: media: seco-cec: fix RC_CORE dependency All other drivers that need RC_CORE have a dependency rather than using 'select', so we should do the same here to avoid circular dependencies as well as this warning about missing dependencies: WARNING: unmet direct dependencies detected for RC_CORE Depends on [n]: INPUT [=n] Selected by [y]: - VIDEO_SECO_RC [=y] && MEDIA_SUPPORT [=y] && CEC_PLATFORM_DRIVERS [=y] && VIDEO_SECO_CEC [=y] Fixes: daef95769b3a ("media: seco-cec: add Consumer-IR support") Signed-off-by: Arnd Bergmann Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index a505e9f5a1e2..b5ccb60cf664 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -650,7 +650,7 @@ config VIDEO_SECO_CEC config VIDEO_SECO_RC bool "SECO Boards IR RC5 support" depends on VIDEO_SECO_CEC - select RC_CORE + depends on RC_CORE help If you say yes here you will get support for the SECO Boards Consumer-IR in seco-cec driver. -- cgit v1.2.3 From c9b7d8f252a5a6f8ca6e948151367cbc7bc4b776 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Thu, 20 Dec 2018 02:48:42 -0500 Subject: media: lgdt3306a: fix a missing check of return value If lgdt3306a_read_reg() fails, the read data in "val" is incorrect, thus shouldn't be further used. The fix inserts a check for the return value of lgdt3306a_read_reg(). If it fails, goto fail. Signed-off-by: Kangjie Lu Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index cee9c83e48de..99c6289ae585 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -1685,7 +1685,10 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, case QAM_256: case QAM_AUTO: /* need to know actual modulation to set proper SNR baseline */ - lgdt3306a_read_reg(state, 0x00a6, &val); + ret = lgdt3306a_read_reg(state, 0x00a6, &val); + if (lg_chkerr(ret)) + goto fail; + if(val & 0x04) ref_snr = 2800; /* QAM-256 28dB */ else -- cgit v1.2.3 From 9502cdf0807058a10029488052b064cecceb7fc9 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Fri, 21 Dec 2018 02:07:20 -0500 Subject: media: mt312: fix a missing check of mt312 reset mt312_reset() may fail. Although it is called in the end of mt312_set_frontend(), we better check its status and return its error code upstream instead of 0. Signed-off-by: Kangjie Lu Reviewed-by: Matthias Schwarzott Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mt312.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index 03e74a729168..bfbb879469f2 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -645,7 +645,9 @@ static int mt312_set_frontend(struct dvb_frontend *fe) if (ret < 0) return ret; - mt312_reset(state, 0); + ret = mt312_reset(state, 0); + if (ret < 0) + return ret; return 0; } -- cgit v1.2.3 From c54dbfcda3059c255f335e75a27d7f5c64e6549e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 22 Dec 2018 09:12:26 -0500 Subject: media: cxd2880-spi: fix two memory leaks of dvb_spi There are two return paths that do not kfree dvb_spi. Fix the memory leaks by returning via the exit label fail_adapter that will free dvi_spi. Detected by CoverityScan, CID#1475991 ("Resource Leak") Fixes: cb496cd472af ("media: cxd2880-spi: Add optional vcc regulator") Signed-off-by: Colin Ian King Acked-by: Yasunari Takiguchi ? Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/spi/cxd2880-spi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index d5c433e20d4a..4077217777f9 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -522,13 +522,15 @@ cxd2880_spi_probe(struct spi_device *spi) dvb_spi->vcc_supply = devm_regulator_get_optional(&spi->dev, "vcc"); if (IS_ERR(dvb_spi->vcc_supply)) { - if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto fail_adapter; + } dvb_spi->vcc_supply = NULL; } else { ret = regulator_enable(dvb_spi->vcc_supply); if (ret) - return ret; + goto fail_adapter; } dvb_spi->spi = spi; -- cgit v1.2.3 From 88903a1abd00e051f3ddfe7b86949882260ddf86 Mon Sep 17 00:00:00 2001 From: Ettore Chimenti Date: Thu, 27 Dec 2018 08:06:35 -0500 Subject: media: secocec: fix ir address shift The actual value of the RC5 System Number (address) is stored in the IR_READ_DATA common register masked with 0x1F00 so it have to be shifted by 8 bits. Signed-off-by: Ettore Chimenti Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/seco-cec/seco-cec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/seco-cec/seco-cec.h b/drivers/media/platform/seco-cec/seco-cec.h index e632c4a2a044..843de8c7dfd4 100644 --- a/drivers/media/platform/seco-cec/seco-cec.h +++ b/drivers/media/platform/seco-cec/seco-cec.h @@ -106,7 +106,7 @@ #define SECOCEC_IR_COMMAND_MASK 0x007F #define SECOCEC_IR_COMMAND_SHL 0 #define SECOCEC_IR_ADDRESS_MASK 0x1F00 -#define SECOCEC_IR_ADDRESS_SHL 7 +#define SECOCEC_IR_ADDRESS_SHL 8 #define SECOCEC_IR_TOGGLE_MASK 0x8000 #define SECOCEC_IR_TOGGLE_SHL 15 -- cgit v1.2.3 From 0f787c12ee7b2b41a74594ed158a0112736f4e4e Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Thu, 27 Dec 2018 13:47:20 -0500 Subject: media: dvb: add return value check on Write16 Write16 can return an error code -1 when the i2c_write fails. The fix checks for these failures and returns the error upstream Signed-off-by: Aditya Pakki Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxd_hard.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 684d428efb0d..0a5b15bee1d7 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -1144,6 +1144,8 @@ static int EnableAndResetMB(struct drxd_state *state) static int InitCC(struct drxd_state *state) { + int status = 0; + if (state->osc_clock_freq == 0 || state->osc_clock_freq > 20000 || (state->osc_clock_freq % 4000) != 0) { @@ -1151,14 +1153,17 @@ static int InitCC(struct drxd_state *state) return -1; } - Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0); - Write16(state, CC_REG_PLL_MODE__A, CC_REG_PLL_MODE_BYPASS_PLL | - CC_REG_PLL_MODE_PUMP_CUR_12, 0); - Write16(state, CC_REG_REF_DIVIDE__A, state->osc_clock_freq / 4000, 0); - Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, 0); - Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0); + status |= Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0); + status |= Write16(state, CC_REG_PLL_MODE__A, + CC_REG_PLL_MODE_BYPASS_PLL | + CC_REG_PLL_MODE_PUMP_CUR_12, 0); + status |= Write16(state, CC_REG_REF_DIVIDE__A, + state->osc_clock_freq / 4000, 0); + status |= Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, + 0); + status |= Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0); - return 0; + return status; } static int ResetECOD(struct drxd_state *state) @@ -1312,7 +1317,10 @@ static int SC_SendCommand(struct drxd_state *state, u16 cmd) int status = 0, ret; u16 errCode; - Write16(state, SC_RA_RAM_CMD__A, cmd, 0); + status = Write16(state, SC_RA_RAM_CMD__A, cmd, 0); + if (status < 0) + return status; + SC_WaitForReady(state); ret = Read16(state, SC_RA_RAM_CMD_ADDR__A, &errCode, 0); @@ -1339,9 +1347,9 @@ static int SC_ProcStartCommand(struct drxd_state *state, break; } SC_WaitForReady(state); - Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0); - Write16(state, SC_RA_RAM_PARAM1__A, param1, 0); - Write16(state, SC_RA_RAM_PARAM0__A, param0, 0); + status |= Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0); + status |= Write16(state, SC_RA_RAM_PARAM1__A, param1, 0); + status |= Write16(state, SC_RA_RAM_PARAM0__A, param0, 0); SC_SendCommand(state, SC_RA_RAM_CMD_PROC_START); } while (0); -- cgit v1.2.3 From 467a37fba93f2b4fe3ab597ff6a517b22b566882 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Thu, 27 Dec 2018 13:58:01 -0500 Subject: media: dvb: Add check on sp8870_readreg In sp8870_set_frontend_parameters, the function sp8870_readreg may return an error when i2c_transfer fails. The fix checks for this error and returns upstream consistent with other invocations. Signed-off-by: Aditya Pakki Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/sp8870.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index 8d31cf3f4f07..270a3c559e08 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -293,7 +293,9 @@ static int sp8870_set_frontend_parameters(struct dvb_frontend *fe) sp8870_writereg(state, 0xc05, reg0xc05); // read status reg in order to clear pending irqs - sp8870_readreg(state, 0x200); + err = sp8870_readreg(state, 0x200); + if (err) + return err; // system controller start sp8870_microcontroller_start(state); -- cgit v1.2.3 From 90917bc8f68ff8357eccda3a53519a53504a99a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Wed, 28 Nov 2018 21:01:45 -0500 Subject: media: i2c: adv748x: reuse power up sequence when initializing CSI-2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the MIPI CSI-2 power up sequence to match the power up sequence in the hardware manual chapter "9.5.1 Power Up Sequence". This change allows the power up functions to be reused when initializing the hardware reducing code duplicating as well aligning with the documentation. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Tested-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 50 +++++++++----------------------- 1 file changed, 13 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 6854d898fdd1..2384f50dacb0 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -234,6 +234,12 @@ static const struct adv748x_reg_value adv748x_power_up_txa_4lane[] = { {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ {ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */ + {ADV748X_PAGE_TXA, 0xdb, 0x10}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0xd6, 0x07}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0xc4, 0x0a}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0x71, 0x33}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0x72, 0x11}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ {ADV748X_PAGE_TXA, 0x1e, 0x40}, /* ADI Required Write */ @@ -263,6 +269,11 @@ static const struct adv748x_reg_value adv748x_power_up_txb_1lane[] = { {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ {ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */ + {ADV748X_PAGE_TXB, 0xd2, 0x40}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0xc4, 0x0a}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0x71, 0x33}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0x72, 0x11}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ {ADV748X_PAGE_TXB, 0x1e, 0x40}, /* ADI Required Write */ @@ -383,25 +394,6 @@ static const struct adv748x_reg_value adv748x_init_txa_4lane[] = { {ADV748X_PAGE_IO, 0x0c, 0xe0}, /* Enable LLC_DLL & Double LLC Timing */ {ADV748X_PAGE_IO, 0x0e, 0xdd}, /* LLC/PIX/SPI PINS TRISTATED AUD */ - {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ - {ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */ - {ADV748X_PAGE_TXA, 0xdb, 0x10}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xd6, 0x07}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xc4, 0x0a}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x71, 0x33}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x72, 0x11}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ - - {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x1e, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ - {ADV748X_PAGE_TXA, 0x00, 0x24 },/* Power-up CSI-TX */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXA, 0xc1, 0x2b}, /* ADI Required Write */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXA, 0x31, 0x80}, /* ADI Required Write */ - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ }; @@ -435,24 +427,6 @@ static const struct adv748x_reg_value adv748x_init_txb_1lane[] = { {ADV748X_PAGE_SDP, 0x31, 0x12}, /* ADI Required Write */ {ADV748X_PAGE_SDP, 0xe6, 0x4f}, /* V bit end pos manually in NTSC */ - {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ - {ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */ - {ADV748X_PAGE_TXB, 0xd2, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xc4, 0x0a}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x71, 0x33}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x72, 0x11}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ - {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x1e, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - - {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ - {ADV748X_PAGE_TXB, 0x00, 0x21 },/* Power-up CSI-TX */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXB, 0xc1, 0x2b}, /* ADI Required Write */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXB, 0x31, 0x80}, /* ADI Required Write */ - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ }; @@ -474,6 +448,7 @@ static int adv748x_reset(struct adv748x_state *state) if (ret) return ret; + adv748x_tx_power(&state->txa, 1); adv748x_tx_power(&state->txa, 0); /* Init and power down TXB */ @@ -481,6 +456,7 @@ static int adv748x_reset(struct adv748x_state *state) if (ret) return ret; + adv748x_tx_power(&state->txb, 1); adv748x_tx_power(&state->txb, 0); /* Disable chip powerdown & Enable HDMI Rx block */ -- cgit v1.2.3 From 6a18865da8e3ebc16b7783c126fbb18be91b5622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Wed, 28 Nov 2018 21:01:46 -0500 Subject: media: i2c: adv748x: store number of CSI-2 lanes described in device tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The adv748x CSI-2 transmitters TXA and TXB can use different number of lanes to transmit data. In order to be able to configure the device correctly this information need to be parsed from device tree and stored in each TX private data structure. TXA supports 1, 2 and 4 lanes while TXB supports 1 lane. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Tested-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 50 ++++++++++++++++++++++++++++++++ drivers/media/i2c/adv748x/adv748x.h | 1 + 2 files changed, 51 insertions(+) (limited to 'drivers') diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 2384f50dacb0..9d80d7f3062b 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "adv748x.h" @@ -521,12 +522,56 @@ void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state, sd->entity.ops = &adv748x_media_ops; } +static int adv748x_parse_csi2_lanes(struct adv748x_state *state, + unsigned int port, + struct device_node *ep) +{ + struct v4l2_fwnode_endpoint vep; + unsigned int num_lanes; + int ret; + + if (port != ADV748X_PORT_TXA && port != ADV748X_PORT_TXB) + return 0; + + vep.bus_type = V4L2_MBUS_CSI2_DPHY; + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &vep); + if (ret) + return ret; + + num_lanes = vep.bus.mipi_csi2.num_data_lanes; + + if (vep.base.port == ADV748X_PORT_TXA) { + if (num_lanes != 1 && num_lanes != 2 && num_lanes != 4) { + adv_err(state, "TXA: Invalid number (%u) of lanes\n", + num_lanes); + return -EINVAL; + } + + state->txa.num_lanes = num_lanes; + adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes); + } + + if (vep.base.port == ADV748X_PORT_TXB) { + if (num_lanes != 1) { + adv_err(state, "TXB: Invalid number (%u) of lanes\n", + num_lanes); + return -EINVAL; + } + + state->txb.num_lanes = num_lanes; + adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes); + } + + return 0; +} + static int adv748x_parse_dt(struct adv748x_state *state) { struct device_node *ep_np = NULL; struct of_endpoint ep; bool out_found = false; bool in_found = false; + int ret; for_each_endpoint_of_node(state->dev->of_node, ep_np) { of_graph_parse_endpoint(ep_np, &ep); @@ -557,6 +602,11 @@ static int adv748x_parse_dt(struct adv748x_state *state) in_found = true; else out_found = true; + + /* Store number of CSI-2 lanes used for TXA and TXB. */ + ret = adv748x_parse_csi2_lanes(state, ep.port, ep_np); + if (ret) + return ret; } return in_found && out_found ? 0 : -ENODEV; diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 39c2fdc3b416..b482c7fe6957 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -79,6 +79,7 @@ struct adv748x_csi2 { struct v4l2_mbus_framefmt format; unsigned int page; unsigned int port; + unsigned int num_lanes; struct media_pad pads[ADV748X_CSI2_NR_PADS]; struct v4l2_ctrl_handler ctrl_hdl; -- cgit v1.2.3 From 0ad5b80cff509360ef9953ac7ce5a56964210c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Wed, 28 Nov 2018 21:01:47 -0500 Subject: media: i2c: adv748x: configure number of lanes used for TXA CSI-2 transmitter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver fixed the TXA CSI-2 transmitter in 4-lane mode while it could operate using 1-, 2- and 4-lanes. Update the driver to support all available modes. The driver makes use of large tables of static register/value writes when powering up/down the TXA and TXB transmitters which include the write to the NUM_LANES register. By converting the tables into functions and using parameters the power up/down functions for TXA and TXB power up/down can be merged and used for both transmitters. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Tested-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 139 ++++++++++++++++--------------- 1 file changed, 70 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 9d80d7f3062b..d94c63cb6a2e 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -125,6 +125,16 @@ int adv748x_write(struct adv748x_state *state, u8 page, u8 reg, u8 value) return regmap_write(state->regmap[page], reg, value); } +static int adv748x_write_check(struct adv748x_state *state, u8 page, u8 reg, + u8 value, int *error) +{ + if (*error) + return *error; + + *error = adv748x_write(state, page, reg, value); + return *error; +} + /* adv748x_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX * size to one or more registers. * @@ -231,79 +241,77 @@ static int adv748x_write_regs(struct adv748x_state *state, * TXA and TXB */ -static const struct adv748x_reg_value adv748x_power_up_txa_4lane[] = { - - {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ - {ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */ - {ADV748X_PAGE_TXA, 0xdb, 0x10}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xd6, 0x07}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xc4, 0x0a}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x71, 0x33}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x72, 0x11}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ - - {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x1e, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ - {ADV748X_PAGE_TXA, 0x00, 0x24 },/* Power-up CSI-TX */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXA, 0xc1, 0x2b}, /* ADI Required Write */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXA, 0x31, 0x80}, /* ADI Required Write */ +static int adv748x_power_up_tx(struct adv748x_csi2 *tx) +{ + struct adv748x_state *state = tx->state; + u8 page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; + int ret = 0; - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; + /* Enable n-lane MIPI */ + adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret); -static const struct adv748x_reg_value adv748x_power_down_txa_4lane[] = { + /* Set Auto DPHY Timing */ + adv748x_write_check(state, page, 0x00, 0xa0 | tx->num_lanes, &ret); - {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x1e, 0x00}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ - {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_TXA, 0xc1, 0x3b}, /* ADI Required Write */ + /* ADI Required Write */ + if (is_txa(tx)) { + adv748x_write_check(state, page, 0xdb, 0x10, &ret); + adv748x_write_check(state, page, 0xd6, 0x07, &ret); + } else { + adv748x_write_check(state, page, 0xd2, 0x40, &ret); + } - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; + adv748x_write_check(state, page, 0xc4, 0x0a, &ret); + adv748x_write_check(state, page, 0x71, 0x33, &ret); + adv748x_write_check(state, page, 0x72, 0x11, &ret); -static const struct adv748x_reg_value adv748x_power_up_txb_1lane[] = { - - {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ - {ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */ - {ADV748X_PAGE_TXB, 0xd2, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xc4, 0x0a}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x71, 0x33}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x72, 0x11}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ - - {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x1e, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ - {ADV748X_PAGE_TXB, 0x00, 0x21 },/* Power-up CSI-TX */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXB, 0xc1, 0x2b}, /* ADI Required Write */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXB, 0x31, 0x80}, /* ADI Required Write */ + /* i2c_dphy_pwdn - 1'b0 */ + adv748x_write_check(state, page, 0xf0, 0x00, &ret); - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; + /* ADI Required Writes*/ + adv748x_write_check(state, page, 0x31, 0x82, &ret); + adv748x_write_check(state, page, 0x1e, 0x40, &ret); -static const struct adv748x_reg_value adv748x_power_down_txb_1lane[] = { + /* i2c_mipi_pll_en - 1'b1 */ + adv748x_write_check(state, page, 0xda, 0x01, &ret); + usleep_range(2000, 2500); - {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x1e, 0x00}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ - {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_TXB, 0xc1, 0x3b}, /* ADI Required Write */ + /* Power-up CSI-TX */ + adv748x_write_check(state, page, 0x00, 0x20 | tx->num_lanes, &ret); + usleep_range(1000, 1500); - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; + /* ADI Required Writes */ + adv748x_write_check(state, page, 0xc1, 0x2b, &ret); + usleep_range(1000, 1500); + adv748x_write_check(state, page, 0x31, 0x80, &ret); -int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) + return ret; +} + +static int adv748x_power_down_tx(struct adv748x_csi2 *tx) { struct adv748x_state *state = tx->state; - const struct adv748x_reg_value *reglist; + u8 page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; + int ret = 0; + + /* ADI Required Writes */ + adv748x_write_check(state, page, 0x31, 0x82, &ret); + adv748x_write_check(state, page, 0x1e, 0x00, &ret); + + /* Enable n-lane MIPI */ + adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret); + + /* i2c_mipi_pll_en - 1'b1 */ + adv748x_write_check(state, page, 0xda, 0x01, &ret); + + /* ADI Required Write */ + adv748x_write_check(state, page, 0xc1, 0x3b, &ret); + + return ret; +} + +int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) +{ int val; if (!is_tx_enabled(tx)) @@ -321,14 +329,7 @@ int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN), "Enabling with unknown bit set"); - if (on) - reglist = is_txa(tx) ? adv748x_power_up_txa_4lane : - adv748x_power_up_txb_1lane; - else - reglist = is_txa(tx) ? adv748x_power_down_txa_4lane : - adv748x_power_down_txb_1lane; - - return adv748x_write_regs(state, reglist); + return on ? adv748x_power_up_tx(tx) : adv748x_power_down_tx(tx); } /* ----------------------------------------------------------------------------- -- cgit v1.2.3 From 2285ec872d9dd5bd6a5c517cfd774be259e5f478 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 15 Jan 2019 17:05:39 -0600 Subject: mlxsw: spectrum_acl_bloom_filter: use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This issue was detected with the help of Coccinelle. Reviewed-by: Ido Schimmel Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c index 505b87846acc..f5c381dcb015 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c @@ -234,8 +234,8 @@ mlxsw_sp_acl_bf_init(struct mlxsw_sp *mlxsw_sp, unsigned int num_erp_banks) * is 2^ACL_MAX_BF_LOG */ bf_bank_size = 1 << MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_BF_LOG); - bf = kzalloc(sizeof(*bf) + bf_bank_size * num_erp_banks * - sizeof(*bf->refcnt), GFP_KERNEL); + bf = kzalloc(struct_size(bf, refcnt, bf_bank_size * num_erp_banks), + GFP_KERNEL); if (!bf) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From faa311e950e37eaa1a3ca30eb42a2aee858ecbf7 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 15 Jan 2019 17:14:29 -0600 Subject: mlxsw: spectrum_nve: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; struct boo entry[]; }; instance = kzalloc(sizeof(struct foo) + count * sizeof(struct boo), GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c index fb1c48c698f2..9019548d731b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -267,8 +267,8 @@ mlxsw_sp_nve_mc_record_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nve_mc_record *mc_record; int err; - mc_record = kzalloc(sizeof(*mc_record) + num_max_entries * - sizeof(struct mlxsw_sp_nve_mc_entry), GFP_KERNEL); + mc_record = kzalloc(struct_size(mc_record, entries, num_max_entries), + GFP_KERNEL); if (!mc_record) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From f74e5a32fa0c03d9f4bb84ea20d0c7be34fe3725 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Thu, 13 Dec 2018 15:24:04 -0500 Subject: media: rcar-vin: Add support for RZ/G2E MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the RZ/G2 User's manual, RZ/G2E and R-Car E3 VIN blocks are identical, therefore use R-Car E3 definitions to add RZ/G2E support. Signed-off-by: Fabrizio Castro Reviewed-by: Simon Horman Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 0e81b557f3b6..b28e3ff191c2 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -1131,6 +1131,10 @@ static const struct rvin_info rcar_info_r8a77995 = { }; static const struct of_device_id rvin_of_id_table[] = { + { + .compatible = "renesas,vin-r8a774c0", + .data = &rcar_info_r8a77990, + }, { .compatible = "renesas,vin-r8a7778", .data = &rcar_info_m1, -- cgit v1.2.3 From 8809b8ceb0bd283c0528a0c7233656b12bcda2dc Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Thu, 13 Dec 2018 15:24:12 -0500 Subject: media: rcar-csi2: Add support for RZ/G2E MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the RZ/G2 User's manual, RZ/G2E and R-Car E3 CSI-2 blocks are identical, therefore use R-Car E3 definitions to add RZ/G2E support. Signed-off-by: Fabrizio Castro Reviewed-by: Simon Horman Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index b2bd0b9627d9..f64528d2be3c 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -985,6 +985,10 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { }; static const struct of_device_id rcar_csi2_of_table[] = { + { + .compatible = "renesas,r8a774c0-csi2", + .data = &rcar_csi2_info_r8a77990, + }, { .compatible = "renesas,r8a7795-csi2", .data = &rcar_csi2_info_r8a7795, -- cgit v1.2.3 From 8db63f3d14dc44c043afc00e5adeb541106ec16b Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 9 Jan 2019 06:24:56 -0500 Subject: media: saa7146: make use of i2c_8bit_addr_from_msg Because it looks neater. Signed-off-by: Peter Rosin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_i2c.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c index 3feddc52c446..df9ebe2a168c 100644 --- a/drivers/media/common/saa7146/saa7146_i2c.c +++ b/drivers/media/common/saa7146/saa7146_i2c.c @@ -54,10 +54,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op) /* loop through all messages */ for(i = 0; i < num; i++) { - /* insert the address of the i2c-slave. - note: we get 7 bit i2c-addresses, - so we have to perform a translation */ - addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0); + addr = i2c_8bit_addr_from_msg(&m[i]); h1 = op_count/3; h2 = op_count%3; op[h1] |= cpu_to_le32( (u8)addr << ((3-h2)*8)); op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2)); -- cgit v1.2.3 From 19c624c6b29e244c418f8b44a711cbf5e82e3cd4 Mon Sep 17 00:00:00 2001 From: Pawe? Chmiel Date: Wed, 9 Jan 2019 13:00:41 -0500 Subject: media: s5p-jpeg: Correct step and max values for V4L2_CID_JPEG_RESTART_INTERVAL This commit corrects max and step values for v4l2 control for V4L2_CID_JPEG_RESTART_INTERVAL. Max should be 0xffff and step should be 1. It was found by using v4l2-compliance tool and checking result of VIDIOC_QUERY_EXT_CTRL/QUERYMENU test. Previously it was complaining that step was bigger than difference between max and min. Fixes: 15f4bc3b1f42 ("[media] s5p-jpeg: Add JPEG controls support") Signed-off-by: Pawe? Chmiel Reviewed-by: Jacek Anaszewski Reviewed-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 85110766043f..0a23b2d19e14 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2005,7 +2005,7 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, V4L2_CID_JPEG_RESTART_INTERVAL, - 0, 3, 0xffff, 0); + 0, 0xffff, 1, 0); if (ctx->jpeg->variant->version == SJPEG_S5P) mask = ~0x06; /* 422, 420 */ } -- cgit v1.2.3 From b9da9b376711f61d0e3c3e419ee348249ca2bd80 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 30 Nov 2018 17:30:48 -0500 Subject: media: ipu3-cio2: Allow probe to succeed if there are no sensors connected The device won't be powered off on systems that have no sensors connected unless it has a driver bound to it. Allow that to happen even if there are no sensors connected to cio2. Reviewed-by: Rajneesh Bhardwaj Tested-by: Rajneesh Bhardwaj Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 447baaebca44..e281e55cdca4 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1810,7 +1810,8 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, /* Register notifier for subdevices we care */ r = cio2_notifier_init(cio2); - if (r) + /* Proceed without sensors connected to allow the device to suspend. */ + if (r && r != -ENODEV) goto fail_cio2_queue_exit; r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq, -- cgit v1.2.3 From 47ee7bde31fa035fbe92a55ca8782a4eafefb0b6 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Wed, 5 Dec 2018 11:32:21 -0500 Subject: media: imx274: fix wrong order in test pattern menus The description of test patterns 11 and 12 are swapped. Checked against the live sensor. Signed-off-by: Luca Ceresoli Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx274.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 5fac7fd32634..95e3d90309e8 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -207,8 +207,8 @@ static const char * const tp_qmenu[] = { "Vertical Stripe (555h / 000h)", "Vertical Stripe (000h / FFFh)", "Vertical Stripe (FFFh / 000h)", - "Horizontal Color Bars", "Vertical Color Bars", + "Horizontal Color Bars", }; /* -- cgit v1.2.3 From b0a7d0e1c09b70a07f3251af7d4e538f310245f4 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 9 Dec 2018 00:20:31 -0500 Subject: media: ov2640: set default window and format code at probe time Set default window and format code at probe time instead of always checking if they have not been set yet when VIDIOC_SUBDEV_G_FMT ioctl is called. This change simplifies the next patch (make VIDIOC_SUBDEV_G_FMT ioctl work with V4L2_SUBDEV_FORMAT_TRY). Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 5d2d6735cc78..1fd893be76f3 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -842,9 +842,6 @@ static int ov2640_set_params(struct i2c_client *client, u8 val; int ret; - if (!win) - return -EINVAL; - switch (code) { case MEDIA_BUS_FMT_RGB565_2X8_BE: dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__); @@ -929,10 +926,6 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; - if (!priv->win) { - priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); - priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; - } mf->width = priv->win->width; mf->height = priv->win->height; @@ -1193,6 +1186,9 @@ static int ov2640_probe(struct i2c_client *client, if (ret) goto err_clk; + priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); + priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; + v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -- cgit v1.2.3 From 8d3b307a150a50cb7c1c905209488dbfe9b6221a Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 9 Dec 2018 00:20:32 -0500 Subject: media: ov2640: make VIDIOC_SUBDEV_G_FMT ioctl work with V4L2_SUBDEV_FORMAT_TRY The VIDIOC_SUBDEV_G_FMT ioctl for this driver doesn't recognize V4L2_SUBDEV_FORMAT_TRY and always works as if V4L2_SUBDEV_FORMAT_ACTIVE is specified. Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 1fd893be76f3..d3f10d92fcc0 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -926,6 +926,15 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mf = v4l2_subdev_get_try_format(sd, cfg, 0); + format->format = *mf; + return 0; +#else + return -ENOTTY; +#endif + } mf->width = priv->win->width; mf->height = priv->win->height; @@ -992,6 +1001,27 @@ out: return ret; } +static int ov2640_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2640_priv *priv = to_ov2640(client); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, cfg, 0); + + try_fmt->width = priv->win->width; + try_fmt->height = priv->win->height; + try_fmt->code = priv->cfmt_code; + try_fmt->colorspace = V4L2_COLORSPACE_SRGB; + try_fmt->field = V4L2_FIELD_NONE; + try_fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + try_fmt->quantization = V4L2_QUANTIZATION_DEFAULT; + try_fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; +#endif + return 0; +} + static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) @@ -1101,6 +1131,7 @@ static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { }; static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { + .init_cfg = ov2640_init_cfg, .enum_mbus_code = ov2640_enum_mbus_code, .get_selection = ov2640_get_selection, .get_fmt = ov2640_get_fmt, -- cgit v1.2.3 From bd0405f929ce4c8b8bd0feca0a8efe144345306b Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 9 Dec 2018 00:20:33 -0500 Subject: media: ov2640: set all mbus format field when G_FMT and S_FMT ioctls This driver doesn't set all members of mbus format field when the VIDIOC_SUBDEV_{S,G}_FMT ioctls are called. This is detected by v4l2-compliance. Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index d3f10d92fcc0..37e7c986af86 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -941,6 +941,9 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, mf->code = priv->cfmt_code; mf->colorspace = V4L2_COLORSPACE_SRGB; mf->field = V4L2_FIELD_NONE; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; return 0; } @@ -967,6 +970,9 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, mf->field = V4L2_FIELD_NONE; mf->colorspace = V4L2_COLORSPACE_SRGB; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; switch (mf->code) { case MEDIA_BUS_FMT_RGB565_2X8_BE: -- cgit v1.2.3 From b7ed3abd808afd90ce8a9701799af8a158846b14 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 2 Nov 2018 12:38:43 -0400 Subject: media: ov5640: Add RAW bayer format support OV5640 sensor supports raw image output (bayer). Configure ISP mux/format registers accordingly. Signed-off-by: Loic Poulain Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 58 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index bef3f3aae0ed..5a909abd0a2d 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -115,6 +115,15 @@ enum ov5640_frame_rate { OV5640_NUM_FRAMERATES, }; +enum ov5640_format_mux { + OV5640_FMT_MUX_YUV422 = 0, + OV5640_FMT_MUX_RGB, + OV5640_FMT_MUX_DITHER, + OV5640_FMT_MUX_RAW_DPC, + OV5640_FMT_MUX_SNR_RAW, + OV5640_FMT_MUX_RAW_CIP, +}; + struct ov5640_pixfmt { u32 code; u32 colorspace; @@ -126,6 +135,10 @@ static const struct ov5640_pixfmt ov5640_formats[] = { { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB, }, }; /* @@ -2200,46 +2213,67 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, struct v4l2_mbus_framefmt *format) { int ret = 0; - bool is_rgb = false; bool is_jpeg = false; - u8 val; + u8 fmt, mux; switch (format->code) { case MEDIA_BUS_FMT_UYVY8_2X8: /* YUV422, UYVY */ - val = 0x3f; + fmt = 0x3f; + mux = OV5640_FMT_MUX_YUV422; break; case MEDIA_BUS_FMT_YUYV8_2X8: /* YUV422, YUYV */ - val = 0x30; + fmt = 0x30; + mux = OV5640_FMT_MUX_YUV422; break; case MEDIA_BUS_FMT_RGB565_2X8_LE: /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ - val = 0x6F; - is_rgb = true; + fmt = 0x6F; + mux = OV5640_FMT_MUX_RGB; break; case MEDIA_BUS_FMT_RGB565_2X8_BE: /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ - val = 0x61; - is_rgb = true; + fmt = 0x61; + mux = OV5640_FMT_MUX_RGB; break; case MEDIA_BUS_FMT_JPEG_1X8: /* YUV422, YUYV */ - val = 0x30; + fmt = 0x30; + mux = OV5640_FMT_MUX_YUV422; is_jpeg = true; break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + /* Raw, BGBG... / GRGR... */ + fmt = 0x00; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SGBRG8_1X8: + /* Raw bayer, GBGB... / RGRG... */ + fmt = 0x01; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SGRBG8_1X8: + /* Raw bayer, GRGR... / BGBG... */ + fmt = 0x02; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SRGGB8_1X8: + /* Raw bayer, RGRG... / GBGB... */ + fmt = 0x03; + mux = OV5640_FMT_MUX_RAW_DPC; + break; default: return -EINVAL; } /* FORMAT CONTROL00: YUV and RGB formatting */ - ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, val); + ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); if (ret) return ret; /* FORMAT MUX CONTROL: ISP YUV or RGB */ - ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, - is_rgb ? 0x01 : 0x00); + ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); if (ret) return ret; -- cgit v1.2.3 From 61da76beef1e4f0b6ba7be4f8d0cf0dac7ce1f55 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 29 Dec 2017 07:22:26 -0500 Subject: media: v4l2: i2c: ov7670: Fix PLL bypass register values The following commits: commit f6dd927f34d6 ("[media] media: ov7670: calculate framerate properly for ov7675") commit 04ee6d92047e ("[media] media: ov7670: add possibility to bypass pll for ov7675") introduced the ability to bypass PLL multiplier and use input clock (xvclk) as pixel clock output frequency for ov7675 sensor. PLL is bypassed using register DBLV[7:6], according to ov7670 and ov7675 sensor manuals. Macros used to set DBLV register seem wrong in the driver, as their values do not match what reported in the datasheet. Fix by changing DBLV_* macros to use bits [7:6] and set bits [3:0] to default 0x0a reserved value (according to datasheets). While at there, remove a write to DBLV register in "ov7675_set_framerate()" that over-writes the previous one to the same register that takes "info->pll_bypass" flag into account instead of setting PLL multiplier to 4x unconditionally. And, while at there, since "info->pll_bypass" is only used in set/get_framerate() functions used by ov7675 only, it is not necessary to check for the device id at probe time to make sure that when using ov7670 "info->pll_bypass" is set to false. Fixes: f6dd927f34d6 ("[media] media: ov7670: calculate framerate properly for ov7675") Signed-off-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7670.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index a70a6ff7b36e..4939a83b50e4 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -160,10 +160,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define REG_GFIX 0x69 /* Fix gain control */ #define REG_DBLV 0x6b /* PLL control an debugging */ -#define DBLV_BYPASS 0x00 /* Bypass PLL */ -#define DBLV_X4 0x01 /* clock x4 */ -#define DBLV_X6 0x10 /* clock x6 */ -#define DBLV_X8 0x11 /* clock x8 */ +#define DBLV_BYPASS 0x0a /* Bypass PLL */ +#define DBLV_X4 0x4a /* clock x4 */ +#define DBLV_X6 0x8a /* clock x6 */ +#define DBLV_X8 0xca /* clock x8 */ #define REG_SCALING_XSC 0x70 /* Test pattern and horizontal scale factor */ #define TEST_PATTTERN_0 0x80 @@ -863,7 +863,7 @@ static int ov7675_set_framerate(struct v4l2_subdev *sd, if (ret < 0) return ret; - return ov7670_write(sd, REG_DBLV, DBLV_X4); + return 0; } static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd, @@ -1801,11 +1801,7 @@ static int ov7670_probe(struct i2c_client *client, if (config->clock_speed) info->clock_speed = config->clock_speed; - /* - * It should be allowed for ov7670 too when it is migrated to - * the new frame rate formula. - */ - if (config->pll_bypass && id->driver_data != MODEL_OV7670) + if (config->pll_bypass) info->pll_bypass = true; if (config->pclk_hb_disable) -- cgit v1.2.3 From 57b0ad9ebe60366b1243bcf612a93a990a3ceff1 Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Thu, 13 Dec 2018 10:39:12 -0500 Subject: media: soc_camera: ov9640: move ov9640 out of soc_camera Initial part of ov9640 transition from soc_camera subsystem to a standalone v4l2 subdevice. The soc_camera version seems to be used only in Palm Zire72 and in (the future) HTC Magician. On these two devices the support is broken as pxa_camera driver doesn't use soc_camera anymore. The other mentions from git grep are "TODOs" (in board-osk.c) or chip names for unsupported sensors on HW which doesn't use soc_camera at all (irelevant). Copy the driver files from soc_camera and mark the original ones in the Kconfig description as obsoleted. Add config option VIDEO_OV9640 to the build files in drivers/media/i2c. Signed-off-by: Petr Cvek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 7 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov9640.c | 738 +++++++++++++++++++++++++++++++++++ drivers/media/i2c/ov9640.h | 208 ++++++++++ drivers/media/i2c/soc_camera/Kconfig | 6 +- 5 files changed, 958 insertions(+), 2 deletions(-) create mode 100644 drivers/media/i2c/ov9640.c create mode 100644 drivers/media/i2c/ov9640.h (limited to 'drivers') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 4c936e129500..119aaee5318b 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -820,6 +820,13 @@ config VIDEO_OV7740 This is a Video4Linux2 sensor driver for the OmniVision OV7740 VGA camera sensor. +config VIDEO_OV9640 + tristate "OmniVision OV9640 sensor support" + depends on I2C && VIDEO_V4L2 + help + This is a Video4Linux2 sensor driver for the OmniVision + OV9640 camera sensor. + config VIDEO_OV9650 tristate "OmniVision OV9650/OV9652 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 65fae7732de0..5639cb2f20aa 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_OV772X) += ov772x.o obj-$(CONFIG_VIDEO_OV7740) += ov7740.o +obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c new file mode 100644 index 000000000000..eb91b8240083 --- /dev/null +++ b/drivers/media/i2c/ov9640.c @@ -0,0 +1,738 @@ +/* + * OmniVision OV96xx Camera Driver + * + * Copyright (C) 2009 Marek Vasut + * + * Based on ov772x camera driver: + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on ov7670 and soc_camera_platform driver, + * + * Copyright 2006-7 Jonathan Corbet + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ov9640.h" + +#define to_ov9640_sensor(sd) container_of(sd, struct ov9640_priv, subdev) + +/* default register setup */ +static const struct ov9640_reg ov9640_regs_dflt[] = { + { OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP }, + { OV9640_COM6, OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS | + OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN }, + { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) }, + { OV9640_ACOM, OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD }, + { OV9640_TSLB, OV9640_TSLB_YUYV_UYVY }, + { OV9640_COM16, OV9640_COM16_RB_AVG }, + + /* Gamma curve P */ + { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 }, + { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 }, + { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, + { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 }, + + /* Gamma curve T */ + { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 }, + { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, + { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e }, + { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 }, +}; + +/* Configurations + * NOTE: for YUV, alter the following registers: + * COM12 |= OV9640_COM12_YUV_AVG + * + * for RGB, alter the following registers: + * COM7 |= OV9640_COM7_RGB + * COM13 |= OV9640_COM13_RGB_AVG + * COM15 |= proper RGB color encoding mode + */ +static const struct ov9640_reg ov9640_regs_qqcif[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) }, + { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP }, + { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, + { OV9640_COM7, OV9640_COM7_QCIF }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_qqvga[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) }, + { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP }, + { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, + { OV9640_COM7, OV9640_COM7_QVGA }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_qcif[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) }, + { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, + { OV9640_COM7, OV9640_COM7_QCIF }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_qvga[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) }, + { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, + { OV9640_COM7, OV9640_COM7_QVGA }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_cif[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) }, + { OV9640_COM3, OV9640_COM3_VP }, + { OV9640_COM7, OV9640_COM7_CIF }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_vga[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) }, + { OV9640_COM3, OV9640_COM3_VP }, + { OV9640_COM7, OV9640_COM7_VGA }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_sxga[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) }, + { OV9640_COM3, OV9640_COM3_VP }, + { OV9640_COM7, 0 }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_yuv[] = { + { OV9640_MTX1, 0x58 }, + { OV9640_MTX2, 0x48 }, + { OV9640_MTX3, 0x10 }, + { OV9640_MTX4, 0x28 }, + { OV9640_MTX5, 0x48 }, + { OV9640_MTX6, 0x70 }, + { OV9640_MTX7, 0x40 }, + { OV9640_MTX8, 0x40 }, + { OV9640_MTX9, 0x40 }, + { OV9640_MTXS, 0x0f }, +}; + +static const struct ov9640_reg ov9640_regs_rgb[] = { + { OV9640_MTX1, 0x71 }, + { OV9640_MTX2, 0x3e }, + { OV9640_MTX3, 0x0c }, + { OV9640_MTX4, 0x33 }, + { OV9640_MTX5, 0x72 }, + { OV9640_MTX6, 0x00 }, + { OV9640_MTX7, 0x2b }, + { OV9640_MTX8, 0x66 }, + { OV9640_MTX9, 0xd2 }, + { OV9640_MTXS, 0x65 }, +}; + +static u32 ov9640_codes[] = { + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + MEDIA_BUS_FMT_RGB565_2X8_LE, +}; + +/* read a register */ +static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int ret; + u8 data = reg; + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &data, + }; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) + goto err; + + msg.flags = I2C_M_RD; + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) + goto err; + + *val = data; + return 0; + +err: + dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg); + return ret; +} + +/* write a register */ +static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val) +{ + int ret; + u8 _val; + unsigned char data[2] = { reg, val }; + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = data, + }; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); + return ret; + } + + /* we have to read the register back ... no idea why, maybe HW bug */ + ret = ov9640_reg_read(client, reg, &_val); + if (ret) + dev_err(&client->dev, + "Failed reading back register 0x%02x!\n", reg); + + return 0; +} + + +/* Read a register, alter its bits, write it back */ +static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset) +{ + u8 val; + int ret; + + ret = ov9640_reg_read(client, reg, &val); + if (ret) { + dev_err(&client->dev, + "[Read]-Modify-Write of register %02x failed!\n", reg); + return ret; + } + + val |= set; + val &= ~unset; + + ret = ov9640_reg_write(client, reg, val); + if (ret) + dev_err(&client->dev, + "Read-Modify-[Write] of register %02x failed!\n", reg); + + return ret; +} + +/* Soft reset the camera. This has nothing to do with the RESET pin! */ +static int ov9640_reset(struct i2c_client *client) +{ + int ret; + + ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET); + if (ret) + dev_err(&client->dev, + "An error occurred while entering soft reset!\n"); + + return ret; +} + +/* Start/Stop streaming from the device */ +static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) +{ + return 0; +} + +/* Set status of additional camera capabilities */ +static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (ctrl->val) + return ov9640_reg_rmw(client, OV9640_MVFP, + OV9640_MVFP_V, 0); + return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); + case V4L2_CID_HFLIP: + if (ctrl->val) + return ov9640_reg_rmw(client, OV9640_MVFP, + OV9640_MVFP_H, 0); + return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); + } + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov9640_get_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u8 val; + + if (reg->reg & ~0xff) + return -EINVAL; + + reg->size = 1; + + ret = ov9640_reg_read(client, reg->reg, &val); + if (ret) + return ret; + + reg->val = (__u64)val; + + return 0; +} + +static int ov9640_set_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg & ~0xff || reg->val & ~0xff) + return -EINVAL; + + return ov9640_reg_write(client, reg->reg, reg->val); +} +#endif + +static int ov9640_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct ov9640_priv *priv = to_ov9640_sensor(sd); + + return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); +} + +/* select nearest higher resolution for capture */ +static void ov9640_res_roundup(u32 *width, u32 *height) +{ + int i; + enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA }; + static const int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; + static const int res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; + + for (i = 0; i < ARRAY_SIZE(res_x); i++) { + if (res_x[i] >= *width && res_y[i] >= *height) { + *width = res_x[i]; + *height = res_y[i]; + return; + } + } + + *width = res_x[SXGA]; + *height = res_y[SXGA]; +} + +/* Prepare necessary register changes depending on color encoding */ +static void ov9640_alter_regs(u32 code, + struct ov9640_reg_alt *alt) +{ + switch (code) { + default: + case MEDIA_BUS_FMT_UYVY8_2X8: + alt->com12 = OV9640_COM12_YUV_AVG; + alt->com13 = OV9640_COM13_Y_DELAY_EN | + OV9640_COM13_YUV_DLY(0x01); + break; + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: + alt->com7 = OV9640_COM7_RGB; + alt->com13 = OV9640_COM13_RGB_AVG; + alt->com15 = OV9640_COM15_RGB_555; + break; + case MEDIA_BUS_FMT_RGB565_2X8_LE: + alt->com7 = OV9640_COM7_RGB; + alt->com13 = OV9640_COM13_RGB_AVG; + alt->com15 = OV9640_COM15_RGB_565; + break; + } +} + +/* Setup registers according to resolution and color encoding */ +static int ov9640_write_regs(struct i2c_client *client, u32 width, + u32 code, struct ov9640_reg_alt *alts) +{ + const struct ov9640_reg *ov9640_regs, *matrix_regs; + int ov9640_regs_len, matrix_regs_len; + int i, ret; + u8 val; + + /* select register configuration for given resolution */ + switch (width) { + case W_QQCIF: + ov9640_regs = ov9640_regs_qqcif; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif); + break; + case W_QQVGA: + ov9640_regs = ov9640_regs_qqvga; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga); + break; + case W_QCIF: + ov9640_regs = ov9640_regs_qcif; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif); + break; + case W_QVGA: + ov9640_regs = ov9640_regs_qvga; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga); + break; + case W_CIF: + ov9640_regs = ov9640_regs_cif; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif); + break; + case W_VGA: + ov9640_regs = ov9640_regs_vga; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga); + break; + case W_SXGA: + ov9640_regs = ov9640_regs_sxga; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga); + break; + default: + dev_err(&client->dev, "Failed to select resolution!\n"); + return -EINVAL; + } + + /* select color matrix configuration for given color encoding */ + if (code == MEDIA_BUS_FMT_UYVY8_2X8) { + matrix_regs = ov9640_regs_yuv; + matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv); + } else { + matrix_regs = ov9640_regs_rgb; + matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb); + } + + /* write register settings into the module */ + for (i = 0; i < ov9640_regs_len; i++) { + val = ov9640_regs[i].val; + + switch (ov9640_regs[i].reg) { + case OV9640_COM7: + val |= alts->com7; + break; + case OV9640_COM12: + val |= alts->com12; + break; + case OV9640_COM13: + val |= alts->com13; + break; + case OV9640_COM15: + val |= alts->com15; + break; + } + + ret = ov9640_reg_write(client, ov9640_regs[i].reg, val); + if (ret) + return ret; + } + + /* write color matrix configuration into the module */ + for (i = 0; i < matrix_regs_len; i++) { + ret = ov9640_reg_write(client, matrix_regs[i].reg, + matrix_regs[i].val); + if (ret) + return ret; + } + + return 0; +} + +/* program default register values */ +static int ov9640_prog_dflt(struct i2c_client *client) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) { + ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg, + ov9640_regs_dflt[i].val); + if (ret) + return ret; + } + + /* wait for the changes to actually happen, 140ms are not enough yet */ + mdelay(150); + + return 0; +} + +/* set the format we will capture in */ +static int ov9640_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov9640_reg_alt alts = {0}; + int ret; + + ov9640_alter_regs(mf->code, &alts); + + ov9640_reset(client); + + ret = ov9640_prog_dflt(client); + if (ret) + return ret; + + return ov9640_write_regs(client, mf->width, mf->code, &alts); +} + +static int ov9640_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + + if (format->pad) + return -EINVAL; + + ov9640_res_roundup(&mf->width, &mf->height); + + mf->field = V4L2_FIELD_NONE; + + switch (mf->code) { + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: + case MEDIA_BUS_FMT_RGB565_2X8_LE: + mf->colorspace = V4L2_COLORSPACE_SRGB; + break; + default: + mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + /* fall through */ + case MEDIA_BUS_FMT_UYVY8_2X8: + mf->colorspace = V4L2_COLORSPACE_JPEG; + break; + } + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov9640_s_fmt(sd, mf); + + cfg->try_fmt = *mf; + return 0; +} + +static int ov9640_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes)) + return -EINVAL; + + code->code = ov9640_codes[code->index]; + return 0; +} + +static int ov9640_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + sel->r.left = 0; + sel->r.top = 0; + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP: + sel->r.width = W_SXGA; + sel->r.height = H_SXGA; + return 0; + default: + return -EINVAL; + } +} + +static int ov9640_video_probe(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov9640_priv *priv = to_ov9640_sensor(sd); + u8 pid, ver, midh, midl; + const char *devname; + int ret; + + ret = ov9640_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + + /* + * check and show product ID and manufacturer ID + */ + + ret = ov9640_reg_read(client, OV9640_PID, &pid); + if (!ret) + ret = ov9640_reg_read(client, OV9640_VER, &ver); + if (!ret) + ret = ov9640_reg_read(client, OV9640_MIDH, &midh); + if (!ret) + ret = ov9640_reg_read(client, OV9640_MIDL, &midl); + if (ret) + goto done; + + switch (VERSION(pid, ver)) { + case OV9640_V2: + devname = "ov9640"; + priv->revision = 2; + break; + case OV9640_V3: + devname = "ov9640"; + priv->revision = 3; + break; + default: + dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); + ret = -ENODEV; + goto done; + } + + dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", + devname, pid, ver, midh, midl); + + ret = v4l2_ctrl_handler_setup(&priv->hdl); + +done: + ov9640_s_power(&priv->subdev, 0); + return ret; +} + +static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { + .s_ctrl = ov9640_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops ov9640_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov9640_get_register, + .s_register = ov9640_set_register, +#endif + .s_power = ov9640_s_power, +}; + +/* Request bus settings on camera side */ +static int ov9640_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov9640_video_ops = { + .s_stream = ov9640_s_stream, + .g_mbus_config = ov9640_g_mbus_config, +}; + +static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { + .enum_mbus_code = ov9640_enum_mbus_code, + .get_selection = ov9640_get_selection, + .set_fmt = ov9640_set_fmt, +}; + +static const struct v4l2_subdev_ops ov9640_subdev_ops = { + .core = &ov9640_core_ops, + .video = &ov9640_video_ops, + .pad = &ov9640_pad_ops, +}; + +/* + * i2c_driver function + */ +static int ov9640_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct ov9640_priv *priv; + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + int ret; + + if (!ssdd) { + dev_err(&client->dev, "Missing platform_data for driver\n"); + return -EINVAL; + } + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); + + v4l2_ctrl_handler_init(&priv->hdl, 2); + v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) + return priv->hdl.error; + + priv->clk = v4l2_clk_get(&client->dev, "mclk"); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + goto eclkget; + } + + ret = ov9640_video_probe(client); + if (ret) { + v4l2_clk_put(priv->clk); +eclkget: + v4l2_ctrl_handler_free(&priv->hdl); + } + + return ret; +} + +static int ov9640_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov9640_priv *priv = to_ov9640_sensor(sd); + + v4l2_clk_put(priv->clk); + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); + return 0; +} + +static const struct i2c_device_id ov9640_id[] = { + { "ov9640", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov9640_id); + +static struct i2c_driver ov9640_i2c_driver = { + .driver = { + .name = "ov9640", + }, + .probe = ov9640_probe, + .remove = ov9640_remove, + .id_table = ov9640_id, +}; + +module_i2c_driver(ov9640_i2c_driver); + +MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); +MODULE_AUTHOR("Marek Vasut "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov9640.h b/drivers/media/i2c/ov9640.h new file mode 100644 index 000000000000..65d13ff17536 --- /dev/null +++ b/drivers/media/i2c/ov9640.h @@ -0,0 +1,208 @@ +/* + * OmniVision OV96xx Camera Header File + * + * Copyright (C) 2009 Marek Vasut + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_MEDIA_VIDEO_OV9640_H__ +#define __DRIVERS_MEDIA_VIDEO_OV9640_H__ + +/* Register definitions */ +#define OV9640_GAIN 0x00 +#define OV9640_BLUE 0x01 +#define OV9640_RED 0x02 +#define OV9640_VFER 0x03 +#define OV9640_COM1 0x04 +#define OV9640_BAVE 0x05 +#define OV9640_GEAVE 0x06 +#define OV9640_RSID 0x07 +#define OV9640_RAVE 0x08 +#define OV9640_COM2 0x09 +#define OV9640_PID 0x0a +#define OV9640_VER 0x0b +#define OV9640_COM3 0x0c +#define OV9640_COM4 0x0d +#define OV9640_COM5 0x0e +#define OV9640_COM6 0x0f +#define OV9640_AECH 0x10 +#define OV9640_CLKRC 0x11 +#define OV9640_COM7 0x12 +#define OV9640_COM8 0x13 +#define OV9640_COM9 0x14 +#define OV9640_COM10 0x15 +/* 0x16 - RESERVED */ +#define OV9640_HSTART 0x17 +#define OV9640_HSTOP 0x18 +#define OV9640_VSTART 0x19 +#define OV9640_VSTOP 0x1a +#define OV9640_PSHFT 0x1b +#define OV9640_MIDH 0x1c +#define OV9640_MIDL 0x1d +#define OV9640_MVFP 0x1e +#define OV9640_LAEC 0x1f +#define OV9640_BOS 0x20 +#define OV9640_GBOS 0x21 +#define OV9640_GROS 0x22 +#define OV9640_ROS 0x23 +#define OV9640_AEW 0x24 +#define OV9640_AEB 0x25 +#define OV9640_VPT 0x26 +#define OV9640_BBIAS 0x27 +#define OV9640_GBBIAS 0x28 +/* 0x29 - RESERVED */ +#define OV9640_EXHCH 0x2a +#define OV9640_EXHCL 0x2b +#define OV9640_RBIAS 0x2c +#define OV9640_ADVFL 0x2d +#define OV9640_ADVFH 0x2e +#define OV9640_YAVE 0x2f +#define OV9640_HSYST 0x30 +#define OV9640_HSYEN 0x31 +#define OV9640_HREF 0x32 +#define OV9640_CHLF 0x33 +#define OV9640_ARBLM 0x34 +/* 0x35..0x36 - RESERVED */ +#define OV9640_ADC 0x37 +#define OV9640_ACOM 0x38 +#define OV9640_OFON 0x39 +#define OV9640_TSLB 0x3a +#define OV9640_COM11 0x3b +#define OV9640_COM12 0x3c +#define OV9640_COM13 0x3d +#define OV9640_COM14 0x3e +#define OV9640_EDGE 0x3f +#define OV9640_COM15 0x40 +#define OV9640_COM16 0x41 +#define OV9640_COM17 0x42 +/* 0x43..0x4e - RESERVED */ +#define OV9640_MTX1 0x4f +#define OV9640_MTX2 0x50 +#define OV9640_MTX3 0x51 +#define OV9640_MTX4 0x52 +#define OV9640_MTX5 0x53 +#define OV9640_MTX6 0x54 +#define OV9640_MTX7 0x55 +#define OV9640_MTX8 0x56 +#define OV9640_MTX9 0x57 +#define OV9640_MTXS 0x58 +/* 0x59..0x61 - RESERVED */ +#define OV9640_LCC1 0x62 +#define OV9640_LCC2 0x63 +#define OV9640_LCC3 0x64 +#define OV9640_LCC4 0x65 +#define OV9640_LCC5 0x66 +#define OV9640_MANU 0x67 +#define OV9640_MANV 0x68 +#define OV9640_HV 0x69 +#define OV9640_MBD 0x6a +#define OV9640_DBLV 0x6b +#define OV9640_GSP 0x6c /* ... till 0x7b */ +#define OV9640_GST 0x7c /* ... till 0x8a */ + +#define OV9640_CLKRC_DPLL_EN 0x80 +#define OV9640_CLKRC_DIRECT 0x40 +#define OV9640_CLKRC_DIV(x) ((x) & 0x3f) + +#define OV9640_PSHFT_VAL(x) ((x) & 0xff) + +#define OV9640_ACOM_2X_ANALOG 0x80 +#define OV9640_ACOM_RSVD 0x12 + +#define OV9640_MVFP_V 0x10 +#define OV9640_MVFP_H 0x20 + +#define OV9640_COM1_HREF_NOSKIP 0x00 +#define OV9640_COM1_HREF_2SKIP 0x04 +#define OV9640_COM1_HREF_3SKIP 0x08 +#define OV9640_COM1_QQFMT 0x20 + +#define OV9640_COM2_SSM 0x10 + +#define OV9640_COM3_VP 0x04 + +#define OV9640_COM4_QQ_VP 0x80 +#define OV9640_COM4_RSVD 0x40 + +#define OV9640_COM5_SYSCLK 0x80 +#define OV9640_COM5_LONGEXP 0x01 + +#define OV9640_COM6_OPT_BLC 0x40 +#define OV9640_COM6_ADBLC_BIAS 0x08 +#define OV9640_COM6_FMT_RST 0x82 +#define OV9640_COM6_ADBLC_OPTEN 0x01 + +#define OV9640_COM7_RAW_RGB 0x01 +#define OV9640_COM7_RGB 0x04 +#define OV9640_COM7_QCIF 0x08 +#define OV9640_COM7_QVGA 0x10 +#define OV9640_COM7_CIF 0x20 +#define OV9640_COM7_VGA 0x40 +#define OV9640_COM7_SCCB_RESET 0x80 + +#define OV9640_TSLB_YVYU_YUYV 0x04 +#define OV9640_TSLB_YUYV_UYVY 0x08 + +#define OV9640_COM12_YUV_AVG 0x04 +#define OV9640_COM12_RSVD 0x40 + +#define OV9640_COM13_GAMMA_NONE 0x00 +#define OV9640_COM13_GAMMA_Y 0x40 +#define OV9640_COM13_GAMMA_RAW 0x80 +#define OV9640_COM13_RGB_AVG 0x20 +#define OV9640_COM13_MATRIX_EN 0x10 +#define OV9640_COM13_Y_DELAY_EN 0x08 +#define OV9640_COM13_YUV_DLY(x) ((x) & 0x07) + +#define OV9640_COM15_OR_00FF 0x00 +#define OV9640_COM15_OR_01FE 0x40 +#define OV9640_COM15_OR_10F0 0xc0 +#define OV9640_COM15_RGB_NORM 0x00 +#define OV9640_COM15_RGB_565 0x10 +#define OV9640_COM15_RGB_555 0x30 + +#define OV9640_COM16_RB_AVG 0x01 + +/* IDs */ +#define OV9640_V2 0x9648 +#define OV9640_V3 0x9649 +#define VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xFF)) + +/* supported resolutions */ +enum { + W_QQCIF = 88, + W_QQVGA = 160, + W_QCIF = 176, + W_QVGA = 320, + W_CIF = 352, + W_VGA = 640, + W_SXGA = 1280 +}; +#define H_SXGA 960 + +/* Misc. structures */ +struct ov9640_reg_alt { + u8 com7; + u8 com12; + u8 com13; + u8 com15; +}; + +struct ov9640_reg { + u8 reg; + u8 val; +}; + +struct ov9640_priv { + struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct v4l2_clk *clk; + + int model; + int revision; +}; + +#endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 7c2aabc8a3f6..7d7b801ab2ce 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -42,10 +42,12 @@ config SOC_CAMERA_OV772X This is a ov772x camera driver config SOC_CAMERA_OV9640 - tristate "ov9640 camera support" + tristate "ov9640 camera support (OBSOLETE)" + default n depends on SOC_CAMERA && I2C help - This is a ov9640 camera driver + This is an obsoleted version of ov9640 camera driver. Please use + the v4l2 standalone one (VIDEO_OV9640). config SOC_CAMERA_OV9740 tristate "ov9740 camera support" -- cgit v1.2.3 From 9f7e55d235b62e95043917fcb86a87064678074c Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Thu, 13 Dec 2018 10:39:13 -0500 Subject: media: i2c: ov9640: drop soc_camera code and switch to v4l2_async This patch removes the dependency on an obsoleted soc_camera from ov9640 driver and changes the code to be a standalone v4l2 async subdevice. It also adds GPIO allocations for power and reset signals (as they are not handled by soc_camera now). The values for waiting on GPIOs (reset and power) settling down were taken from the datasheet (> 1 ms after HW/SW reset). The upper limit was chosen as an arbitrary value. Also one occurrence of mdelay() was changed to msleep(). The delays were successfully tested on a real hardware. The patch makes ov9640 sensor again compatible with the pxa_camera driver. Signed-off-by: Petr Cvek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9640.c | 76 ++++++++++++++++++++++++++++++++-------------- drivers/media/i2c/ov9640.h | 2 ++ 2 files changed, 55 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index eb91b8240083..1f7cf01d037f 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -9,6 +9,7 @@ * Kuninori Morimoto * * Based on ov7670 and soc_camera_platform driver, + * transition from soc_camera to pxa_camera based on mt9m111 * * Copyright 2006-7 Jonathan Corbet * Copyright (C) 2008 Magnus Damm @@ -27,10 +28,14 @@ #include #include -#include +#include #include #include #include +#include +#include + +#include #include "ov9640.h" @@ -323,11 +328,23 @@ static int ov9640_set_register(struct v4l2_subdev *sd, static int ov9640_s_power(struct v4l2_subdev *sd, int on) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct ov9640_priv *priv = to_ov9640_sensor(sd); - - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); + int ret = 0; + + if (on) { + gpiod_set_value(priv->gpio_power, 1); + usleep_range(1000, 2000); + ret = v4l2_clk_enable(priv->clk); + usleep_range(1000, 2000); + gpiod_set_value(priv->gpio_reset, 0); + } else { + gpiod_set_value(priv->gpio_reset, 1); + usleep_range(1000, 2000); + v4l2_clk_disable(priv->clk); + usleep_range(1000, 2000); + gpiod_set_value(priv->gpio_power, 0); + } + return ret; } /* select nearest higher resolution for capture */ @@ -475,7 +492,7 @@ static int ov9640_prog_dflt(struct i2c_client *client) } /* wait for the changes to actually happen, 140ms are not enough yet */ - mdelay(150); + msleep(150); return 0; } @@ -630,14 +647,10 @@ static const struct v4l2_subdev_core_ops ov9640_core_ops = { static int ov9640_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH; cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); return 0; } @@ -666,18 +679,27 @@ static int ov9640_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov9640_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); int ret; - if (!ssdd) { - dev_err(&client->dev, "Missing platform_data for driver\n"); - return -EINVAL; - } - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&client->dev, sizeof(*priv), + GFP_KERNEL); if (!priv) return -ENOMEM; + priv->gpio_power = devm_gpiod_get(&client->dev, "Camera power", + GPIOD_OUT_LOW); + if (IS_ERR_OR_NULL(priv->gpio_power)) { + ret = PTR_ERR(priv->gpio_power); + return ret; + } + + priv->gpio_reset = devm_gpiod_get(&client->dev, "Camera reset", + GPIOD_OUT_HIGH); + if (IS_ERR_OR_NULL(priv->gpio_reset)) { + ret = PTR_ERR(priv->gpio_reset); + return ret; + } + v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 2); @@ -696,12 +718,20 @@ static int ov9640_probe(struct i2c_client *client, } ret = ov9640_video_probe(client); - if (ret) { - v4l2_clk_put(priv->clk); -eclkget: - v4l2_ctrl_handler_free(&priv->hdl); - } + if (ret) + goto eprobe; + priv->subdev.dev = &client->dev; + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret) + goto eprobe; + + return 0; + +eprobe: + v4l2_clk_put(priv->clk); +eclkget: + v4l2_ctrl_handler_free(&priv->hdl); return ret; } @@ -711,7 +741,7 @@ static int ov9640_remove(struct i2c_client *client) struct ov9640_priv *priv = to_ov9640_sensor(sd); v4l2_clk_put(priv->clk); - v4l2_device_unregister_subdev(&priv->subdev); + v4l2_async_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); return 0; } diff --git a/drivers/media/i2c/ov9640.h b/drivers/media/i2c/ov9640.h index 65d13ff17536..be5e4b29ac69 100644 --- a/drivers/media/i2c/ov9640.h +++ b/drivers/media/i2c/ov9640.h @@ -200,6 +200,8 @@ struct ov9640_priv { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; struct v4l2_clk *clk; + struct gpio_desc *gpio_power; + struct gpio_desc *gpio_reset; int model; int revision; -- cgit v1.2.3 From f8de593d5348259c25bb383e80698213b9af4ff0 Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Thu, 13 Dec 2018 10:39:15 -0500 Subject: media: i2c: ov9640: add missing SPDX identifiers Add missing SPDX identifiers to .c and .h files of the sensor driver. Signed-off-by: Petr Cvek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9640.c | 5 +---- drivers/media/i2c/ov9640.h | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 1f7cf01d037f..9a6fa609e8c4 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * OmniVision OV96xx Camera Driver * @@ -14,10 +15,6 @@ * Copyright 2006-7 Jonathan Corbet * Copyright (C) 2008 Magnus Damm * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/media/i2c/ov9640.h b/drivers/media/i2c/ov9640.h index be5e4b29ac69..a8ed6992c1a8 100644 --- a/drivers/media/i2c/ov9640.h +++ b/drivers/media/i2c/ov9640.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * OmniVision OV96xx Camera Header File * * Copyright (C) 2009 Marek Vasut - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __DRIVERS_MEDIA_VIDEO_OV9640_H__ -- cgit v1.2.3 From 74d01576fc85a5a5e7ea8c4de276c7db0d6abc1a Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Thu, 13 Dec 2018 10:39:16 -0500 Subject: media: i2c: ov9640: change array index or length variables to unsigned The driver uses variables to store frame resolutions and to indexing various arrays. These should be unsigned. Signed-off-by: Petr Cvek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9640.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 9a6fa609e8c4..08f3f8247759 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -347,10 +347,10 @@ static int ov9640_s_power(struct v4l2_subdev *sd, int on) /* select nearest higher resolution for capture */ static void ov9640_res_roundup(u32 *width, u32 *height) { - int i; + unsigned int i; enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA }; - static const int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; - static const int res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; + static const u32 res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; + static const u32 res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; for (i = 0; i < ARRAY_SIZE(res_x); i++) { if (res_x[i] >= *width && res_y[i] >= *height) { @@ -393,8 +393,9 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width, u32 code, struct ov9640_reg_alt *alts) { const struct ov9640_reg *ov9640_regs, *matrix_regs; - int ov9640_regs_len, matrix_regs_len; - int i, ret; + unsigned int ov9640_regs_len, matrix_regs_len; + unsigned int i; + int ret; u8 val; /* select register configuration for given resolution */ @@ -479,7 +480,8 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width, /* program default register values */ static int ov9640_prog_dflt(struct i2c_client *client) { - int i, ret; + unsigned int i; + int ret; for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) { ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg, -- cgit v1.2.3 From 856b0b8ffbf69d7b146a62669904576538d74aac Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Thu, 13 Dec 2018 10:39:17 -0500 Subject: media: i2c: ov9640: add space before return for better clarity Some returns were adjoined to unrelated code blocks. This patch adds a space inbetween. Signed-off-by: Petr Cvek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9640.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 08f3f8247759..2839aa3b4fb4 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -286,6 +286,7 @@ static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) OV9640_MVFP_H, 0); return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); } + return -EINVAL; } @@ -341,6 +342,7 @@ static int ov9640_s_power(struct v4l2_subdev *sd, int on) usleep_range(1000, 2000); gpiod_set_value(priv->gpio_power, 0); } + return ret; } @@ -545,6 +547,7 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd, return ov9640_s_fmt(sd, mf); cfg->try_fmt = *mf; + return 0; } @@ -556,6 +559,7 @@ static int ov9640_enum_mbus_code(struct v4l2_subdev *sd, return -EINVAL; code->code = ov9640_codes[code->index]; + return 0; } @@ -731,6 +735,7 @@ eprobe: v4l2_clk_put(priv->clk); eclkget: v4l2_ctrl_handler_free(&priv->hdl); + return ret; } -- cgit v1.2.3 From 95531e462288a9afdcb494abf6d1d123f5a4ff1c Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Thu, 13 Dec 2018 10:39:18 -0500 Subject: media: i2c: ov9640: make array of supported formats constant An array which defines sensor's supported formats is not written anywhere, so it can be constant. Signed-off-by: Petr Cvek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 2839aa3b4fb4..9739fa8d433a 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -161,7 +161,7 @@ static const struct ov9640_reg ov9640_regs_rgb[] = { { OV9640_MTXS, 0x65 }, }; -static u32 ov9640_codes[] = { +static const u32 ov9640_codes[] = { MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, MEDIA_BUS_FMT_RGB565_2X8_LE, -- cgit v1.2.3 From ffe305d261f4d96eb851f1cad860d845edfaef25 Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Thu, 13 Dec 2018 10:39:19 -0500 Subject: media: i2c: ov9640: fix missing error handling in probe Control handlers registration lacked error path with v4l2_ctrl_handler_free() call. Fix it by using goto to alread existing v4l2_ctrl_handler_free() call. Signed-off-by: Petr Cvek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9640.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 9739fa8d433a..c183273fd332 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -710,14 +710,18 @@ static int ov9640_probe(struct i2c_client *client, V4L2_CID_VFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + + if (priv->hdl.error) { + ret = priv->hdl.error; + goto ectrlinit; + } + priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) - return priv->hdl.error; priv->clk = v4l2_clk_get(&client->dev, "mclk"); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); - goto eclkget; + goto ectrlinit; } ret = ov9640_video_probe(client); @@ -733,7 +737,7 @@ static int ov9640_probe(struct i2c_client *client, eprobe: v4l2_clk_put(priv->clk); -eclkget: +ectrlinit: v4l2_ctrl_handler_free(&priv->hdl); return ret; -- cgit v1.2.3 From 16aaf112d3e53c9e450cbfc6063b407d1686fe1a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 13 Dec 2018 15:29:34 -0500 Subject: media: ov9640: Wrap long and unwrap short lines, align wrapped lines correctly Some little style fixup work. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9640.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index c183273fd332..d6831f28378b 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -271,19 +271,20 @@ static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) /* Set status of additional camera capabilities */ static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) { - struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); + struct ov9640_priv *priv = container_of(ctrl->handler, + struct ov9640_priv, hdl); struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->val) return ov9640_reg_rmw(client, OV9640_MVFP, - OV9640_MVFP_V, 0); + OV9640_MVFP_V, 0); return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); case V4L2_CID_HFLIP: if (ctrl->val) return ov9640_reg_rmw(client, OV9640_MVFP, - OV9640_MVFP_H, 0); + OV9640_MVFP_H, 0); return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); } @@ -471,7 +472,7 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width, /* write color matrix configuration into the module */ for (i = 0; i < matrix_regs_len; i++) { ret = ov9640_reg_write(client, matrix_regs[i].reg, - matrix_regs[i].val); + matrix_regs[i].val); if (ret) return ret; } @@ -487,7 +488,7 @@ static int ov9640_prog_dflt(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) { ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg, - ov9640_regs_dflt[i].val); + ov9640_regs_dflt[i].val); if (ret) return ret; } @@ -684,8 +685,7 @@ static int ov9640_probe(struct i2c_client *client, struct ov9640_priv *priv; int ret; - priv = devm_kzalloc(&client->dev, sizeof(*priv), - GFP_KERNEL); + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -707,9 +707,9 @@ static int ov9640_probe(struct i2c_client *client, v4l2_ctrl_handler_init(&priv->hdl, 2); v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); + V4L2_CID_VFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); + V4L2_CID_HFLIP, 0, 1, 1, 0); if (priv->hdl.error) { ret = priv->hdl.error; @@ -751,6 +751,7 @@ static int ov9640_remove(struct i2c_client *client) v4l2_clk_put(priv->clk); v4l2_async_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); + return 0; } -- cgit v1.2.3 From 2d9a43be4a2e9e5ba0f9810de81ffe5436dc3eff Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 30 Nov 2018 02:58:45 -0500 Subject: media: sun6i: Add H3 compatible The CSI controller found on the H3 (and H5) is a reduced version of the one found on the A31. It only has 1 channel, instead of 4 channels for time-multiplexed BT.656. Since the H3 is a reduced version, it cannot "fallback" to a compatible that implements more features than it supports. Add a compatible string entry for the H3. Signed-off-by: Chen-Yu Tsai Reviewed-by: Jagan Teki Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 6950585edb5a..ee882b66a5ea 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -893,6 +893,7 @@ static int sun6i_csi_remove(struct platform_device *pdev) static const struct of_device_id sun6i_csi_of_match[] = { { .compatible = "allwinner,sun6i-a31-csi", }, + { .compatible = "allwinner,sun8i-h3-csi", }, { .compatible = "allwinner,sun8i-v3s-csi", }, {}, }; -- cgit v1.2.3 From 8f57763e521c2798a8e1c91efb822fd6e0fb3b72 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 7 Jan 2019 06:07:05 -0500 Subject: media: ipu3-cio2, dw9714: Remove Jian Xu's e-mail Jian Xu has left the company. Remove his e-mail address that no longer works. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/dw9714.c | 2 +- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c index 26d83693a681..3f0b082f863f 100644 --- a/drivers/media/i2c/dw9714.c +++ b/drivers/media/i2c/dw9714.c @@ -267,7 +267,7 @@ static struct i2c_driver dw9714_i2c_driver = { module_i2c_driver(dw9714_i2c_driver); MODULE_AUTHOR("Tianshu Qiu "); -MODULE_AUTHOR("Jian Xu Zheng "); +MODULE_AUTHOR("Jian Xu Zheng"); MODULE_AUTHOR("Yuning Pu "); MODULE_AUTHOR("Jouni Ukkonen "); MODULE_AUTHOR("Tommi Franttila "); diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index e281e55cdca4..01ebd3550d88 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -2048,7 +2048,7 @@ module_pci_driver(cio2_pci_driver); MODULE_AUTHOR("Tuukka Toivonen "); MODULE_AUTHOR("Tianshu Qiu "); -MODULE_AUTHOR("Jian Xu Zheng "); +MODULE_AUTHOR("Jian Xu Zheng"); MODULE_AUTHOR("Yuning Pu "); MODULE_AUTHOR("Yong Zhi "); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6f7f1bff2d9896fc743e7e110e9ab288f5ad7cbf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 14 Jan 2019 08:50:54 -0500 Subject: media: vivid: disable VB2_USERPTR if dma_contig was configured It makes no sense to support the USERPTR memory model if the vivid instance was configured as dma_contig. Disable it if this is the case. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index c931f007e5b0..745ba6678b40 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -1094,7 +1094,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q = &dev->vb_vid_cap_q; q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vid_cap_qops; @@ -1115,7 +1117,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q = &dev->vb_vid_out_q; q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vid_out_qops; @@ -1136,7 +1140,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q = &dev->vb_vbi_cap_q; q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE : V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vbi_cap_qops; @@ -1157,7 +1163,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q = &dev->vb_vbi_out_q; q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT : V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vbi_out_qops; @@ -1177,7 +1185,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) /* initialize sdr_cap queue */ q = &dev->vb_sdr_cap_q; q->type = V4L2_BUF_TYPE_SDR_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_sdr_cap_qops; -- cgit v1.2.3 From 987303cc172a0899bc25b913d1315809a9fb8d17 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 14 Jan 2019 11:23:52 -0500 Subject: media: vivid: take data_offset into account for video output The video output sizeimage calculation did not take data_offset into account. This can cause problems with video loopback or exporting output buffers for use as dmabuf import buffers since the output buffer size is now too small. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-out.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index ea250aee2b2e..55c0628ee9e1 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -28,11 +28,12 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct vivid_fmt *vfmt = dev->fmt_out; unsigned planes = vfmt->buffers; unsigned h = dev->fmt_out_rect.height; - unsigned size = dev->bytesperline_out[0] * h; + unsigned int size = dev->bytesperline_out[0] * h + vfmt->data_offset[0]; unsigned p; for (p = vfmt->buffers; p < vfmt->planes; p++) - size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; + size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p] + + vfmt->data_offset[p]; if (dev->field_out == V4L2_FIELD_ALTERNATE) { /* @@ -62,12 +63,14 @@ static int vid_out_queue_setup(struct vb2_queue *vq, if (sizes[0] < size) return -EINVAL; for (p = 1; p < planes; p++) { - if (sizes[p] < dev->bytesperline_out[p] * h) + if (sizes[p] < dev->bytesperline_out[p] * h + + vfmt->data_offset[p]) return -EINVAL; } } else { for (p = 0; p < planes; p++) - sizes[p] = p ? dev->bytesperline_out[p] * h : size; + sizes[p] = p ? dev->bytesperline_out[p] * h + + vfmt->data_offset[p] : size; } if (vq->num_buffers + *nbuffers < 2) @@ -321,7 +324,8 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv, for (p = 0; p < mp->num_planes; p++) { mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; mp->plane_fmt[p].sizeimage = - mp->plane_fmt[p].bytesperline * mp->height; + mp->plane_fmt[p].bytesperline * mp->height + + fmt->data_offset[p]; } for (p = fmt->buffers; p < fmt->planes; p++) { unsigned stride = dev->bytesperline_out[p]; @@ -399,7 +403,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, pfmt[p].bytesperline = bytesperline; pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / - fmt->vdownsampling[p]; + fmt->vdownsampling[p] + fmt->data_offset[p]; memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } -- cgit v1.2.3 From 3f122df4a2ba6704ccf51f5caec583443514644f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 Jan 2019 06:37:03 -0500 Subject: media: vivid: do not implement VIDIOC_S_PARM for output streams v4l2_compliance gave a warning for the S_PARM test for output streams: warn: v4l2-test-formats.cpp(1235): S_PARM is supported for buftype 2, but not for ENUM_FRAMEINTERVALS The reason is that vivid mapped s_parm for output streams to g_parm. But if S_PARM doesn't actually change anything, then it shouldn't be enabled at all. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 745ba6678b40..29e7b14fa704 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -371,7 +371,7 @@ static int vidioc_s_parm(struct file *file, void *fh, if (vdev->vfl_dir == VFL_DIR_RX) return vivid_vid_cap_s_parm(file, fh, parm); - return vivid_vid_out_g_parm(file, fh, parm); + return -ENOTTY; } static int vidioc_log_status(struct file *file, void *fh) -- cgit v1.2.3 From 86824694184642a4dc1be0c050df9854da5f51d3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 Jan 2019 06:43:12 -0500 Subject: media: vim2m: the v4l2_m2m_buf_copy_data args were swapped The buffer arguments to v4l2_m2m_buf_copy_data args were swapped. The reason is confusing naming conventions in vim2m. It certainly could be improved. Fixes: 7aca565ee3d0 ("media: vim2m: use v4l2_m2m_buf_copy_data") Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vim2m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index 33397d4a1402..a7a152fb3075 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -241,7 +241,7 @@ static int device_process(struct vim2m_ctx *ctx, out_vb->sequence = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++; in_vb->sequence = q_data->sequence++; - v4l2_m2m_buf_copy_data(out_vb, in_vb, true); + v4l2_m2m_buf_copy_data(in_vb, out_vb, true); switch (ctx->mode) { case MEM2MEM_HFLIP | MEM2MEM_VFLIP: -- cgit v1.2.3 From 4d4abf064d676dcc27952ed90f4f50d7087318c7 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 14 Dec 2018 11:40:24 -0500 Subject: media: gspca: ov534: replace msleep(10) with usleep_range For short waits, usleep_range should be used instead of msleep, see Documentation/timers/timers-howto.txt. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/ov534.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index d06dc0755b9a..44f06a58bb67 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -679,7 +679,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev) int i; for (i = 0; i < 5; i++) { - msleep(10); + usleep_range(10000, 20000); data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); switch (data) { @@ -1277,7 +1277,7 @@ static int sd_init(struct gspca_dev *gspca_dev) /* reset sensor */ sccb_reg_write(gspca_dev, 0x12, 0x80); - msleep(10); + usleep_range(10000, 20000); /* probe the sensor */ sccb_reg_read(gspca_dev, 0x0a); -- cgit v1.2.3 From fc78e0b2471d6efa19f896d7c93a8ecda9913ddd Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 14 Dec 2018 11:40:25 -0500 Subject: media: gspca: support multiple pixel formats in ENUM_FRAMEINTERVALS If a driver supports multiple pixel formats with the same frame size, ENUM_FRAMEINTERVALS will currently only work for the first pixel format. Fix this by adding pixelformat support to wxh_to_mode(). Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 3137f5d89d80..13361cfa6903 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -912,13 +912,14 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev) } static int wxh_to_mode(struct gspca_dev *gspca_dev, - int width, int height) + int width, int height, u32 pixelformat) { int i; for (i = 0; i < gspca_dev->cam.nmodes; i++) { if (width == gspca_dev->cam.cam_mode[i].width - && height == gspca_dev->cam.cam_mode[i].height) + && height == gspca_dev->cam.cam_mode[i].height + && pixelformat == gspca_dev->cam.cam_mode[i].pixelformat) return i; } return -EINVAL; @@ -1152,7 +1153,8 @@ static int vidioc_enum_frameintervals(struct file *filp, void *priv, int mode; __u32 i; - mode = wxh_to_mode(gspca_dev, fival->width, fival->height); + mode = wxh_to_mode(gspca_dev, fival->width, fival->height, + fival->pixel_format); if (mode < 0) return -EINVAL; -- cgit v1.2.3 From d4809b778a0899f732e808e60b3a42cfce0b5e40 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 14 Dec 2018 11:40:26 -0500 Subject: media: gspca: support multiple pixel formats in TRY_FMT If a driver supports multiple pixel formats with the same frame size, TRY_FMT will currently always return the first pixel format. Fix this by adding pixelformat support to wxh_to_nearest_mode(). Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 13361cfa6903..ac70b36d67b7 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -926,10 +926,16 @@ static int wxh_to_mode(struct gspca_dev *gspca_dev, } static int wxh_to_nearest_mode(struct gspca_dev *gspca_dev, - int width, int height) + int width, int height, u32 pixelformat) { int i; + for (i = gspca_dev->cam.nmodes; --i > 0; ) { + if (width >= gspca_dev->cam.cam_mode[i].width + && height >= gspca_dev->cam.cam_mode[i].height + && pixelformat == gspca_dev->cam.cam_mode[i].pixelformat) + return i; + } for (i = gspca_dev->cam.nmodes; --i > 0; ) { if (width >= gspca_dev->cam.cam_mode[i].width && height >= gspca_dev->cam.cam_mode[i].height) @@ -1059,7 +1065,7 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, fmt->fmt.pix.pixelformat, w, h); /* search the nearest mode for width and height */ - mode = wxh_to_nearest_mode(gspca_dev, w, h); + mode = wxh_to_nearest_mode(gspca_dev, w, h, fmt->fmt.pix.pixelformat); /* OK if right palette */ if (gspca_dev->cam.cam_mode[mode].pixelformat -- cgit v1.2.3 From c53304f2ce702091d47fffbac52d351ff8094c68 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 14 Dec 2018 11:40:27 -0500 Subject: media: gspca: ov543-ov772x: move video format specific registers into bridge_start In preparation for adding SGBRG8 as a second video format besides YUYV, move video format specific register settings from the bridge_init array into the bridge_start arrays. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/ov534.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 44f06a58bb67..077c49a74709 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -411,9 +411,7 @@ static const u8 sensor_start_qvga_767x[][2] = { }; static const u8 bridge_init_772x[][2] = { - { 0xc2, 0x0c }, { 0x88, 0xf8 }, - { 0xc3, 0x69 }, { 0x89, 0xff }, { 0x76, 0x03 }, { 0x92, 0x01 }, @@ -439,7 +437,6 @@ static const u8 bridge_init_772x[][2] = { { 0x1f, 0x81 }, { 0x34, 0x05 }, { 0xe3, 0x04 }, - { 0x88, 0x00 }, { 0x89, 0x00 }, { 0x76, 0x00 }, { 0xe7, 0x2e }, @@ -460,13 +457,7 @@ static const u8 bridge_init_772x[][2] = { { 0x1d, 0x08 }, /* turn on UVC header */ { 0x1d, 0x0e }, /* .. */ - { 0x8d, 0x1c }, - { 0x8e, 0x80 }, { 0xe5, 0x04 }, - - { 0xc0, 0x50 }, - { 0xc1, 0x3c }, - { 0xc2, 0x0c }, }; static const u8 sensor_init_772x[][2] = { { 0x12, 0x80 }, @@ -562,6 +553,7 @@ static const u8 sensor_init_772x[][2] = { { 0x0c, 0xd0 } }; static const u8 bridge_start_vga_772x[][2] = { + {0x88, 0x00}, {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, @@ -569,8 +561,12 @@ static const u8 bridge_start_vga_772x[][2] = { {0x1d, 0x02}, {0x1d, 0x58}, {0x1d, 0x00}, + {0x8d, 0x1c}, + {0x8e, 0x80}, {0xc0, 0x50}, {0xc1, 0x3c}, + {0xc2, 0x0c}, + {0xc3, 0x69}, }; static const u8 sensor_start_vga_772x[][2] = { {0x12, 0x00}, @@ -583,6 +579,7 @@ static const u8 sensor_start_vga_772x[][2] = { {0x65, 0x20}, }; static const u8 bridge_start_qvga_772x[][2] = { + {0x88, 0x00}, {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, @@ -590,8 +587,12 @@ static const u8 bridge_start_qvga_772x[][2] = { {0x1d, 0x01}, {0x1d, 0x4b}, {0x1d, 0x00}, + {0x8d, 0x1c}, + {0x8e, 0x80}, {0xc0, 0x28}, {0xc1, 0x1e}, + {0xc2, 0x0c}, + {0xc3, 0x69}, }; static const u8 sensor_start_qvga_772x[][2] = { {0x12, 0x40}, -- cgit v1.2.3 From 52b756aa90713e4d403ef841a9403610de3fd5b5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 14 Dec 2018 11:40:28 -0500 Subject: media: gspca: ov534-ov772x: add SGBRG8 bayer mode support Add support to pass through the sensor's native SGBRG8 bayer pattern, allowing to cut the required USB bandwidth in half. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/ov534.c | 115 ++++++++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 077c49a74709..5b73f7f58ae6 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -103,6 +103,16 @@ static const struct v4l2_pix_format ov772x_mode[] = { .sizeimage = 640 * 480 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, + {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, }; static const struct v4l2_pix_format ov767x_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -127,6 +137,14 @@ static const struct framerates ov772x_framerates[] = { .rates = vga_rates, .nrates = ARRAY_SIZE(vga_rates), }, + { /* 320x240 SGBRG8 */ + .rates = qvga_rates, + .nrates = ARRAY_SIZE(qvga_rates), + }, + { /* 640x480 SGBRG8 */ + .rates = vga_rates, + .nrates = ARRAY_SIZE(vga_rates), + }, }; struct reg_array { @@ -552,7 +570,7 @@ static const u8 sensor_init_772x[][2] = { { 0x8e, 0x00 }, /* De-noise threshold */ { 0x0c, 0xd0 } }; -static const u8 bridge_start_vga_772x[][2] = { +static const u8 bridge_start_vga_yuyv_772x[][2] = { {0x88, 0x00}, {0x1c, 0x00}, {0x1d, 0x40}, @@ -568,7 +586,7 @@ static const u8 bridge_start_vga_772x[][2] = { {0xc2, 0x0c}, {0xc3, 0x69}, }; -static const u8 sensor_start_vga_772x[][2] = { +static const u8 sensor_start_vga_yuyv_772x[][2] = { {0x12, 0x00}, {0x17, 0x26}, {0x18, 0xa0}, @@ -577,8 +595,9 @@ static const u8 sensor_start_vga_772x[][2] = { {0x29, 0xa0}, {0x2c, 0xf0}, {0x65, 0x20}, + {0x67, 0x00}, }; -static const u8 bridge_start_qvga_772x[][2] = { +static const u8 bridge_start_qvga_yuyv_772x[][2] = { {0x88, 0x00}, {0x1c, 0x00}, {0x1d, 0x40}, @@ -594,7 +613,7 @@ static const u8 bridge_start_qvga_772x[][2] = { {0xc2, 0x0c}, {0xc3, 0x69}, }; -static const u8 sensor_start_qvga_772x[][2] = { +static const u8 sensor_start_qvga_yuyv_772x[][2] = { {0x12, 0x40}, {0x17, 0x3f}, {0x18, 0x50}, @@ -603,6 +622,61 @@ static const u8 sensor_start_qvga_772x[][2] = { {0x29, 0x50}, {0x2c, 0x78}, {0x65, 0x2f}, + {0x67, 0x00}, +}; +static const u8 bridge_start_vga_gbrg_772x[][2] = { + {0x88, 0x08}, + {0x1c, 0x00}, + {0x1d, 0x00}, + {0x1d, 0x02}, + {0x1d, 0x00}, + {0x1d, 0x01}, + {0x1d, 0x2c}, + {0x1d, 0x00}, + {0x8d, 0x00}, + {0x8e, 0x00}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0xc2, 0x01}, + {0xc3, 0x01}, +}; +static const u8 sensor_start_vga_gbrg_772x[][2] = { + {0x12, 0x01}, + {0x17, 0x26}, + {0x18, 0xa0}, + {0x19, 0x07}, + {0x1a, 0xf0}, + {0x29, 0xa0}, + {0x2c, 0xf0}, + {0x65, 0x20}, + {0x67, 0x02}, +}; +static const u8 bridge_start_qvga_gbrg_772x[][2] = { + {0x88, 0x08}, + {0x1c, 0x00}, + {0x1d, 0x00}, + {0x1d, 0x02}, + {0x1d, 0x00}, + {0x1d, 0x00}, + {0x1d, 0x4b}, + {0x1d, 0x00}, + {0x8d, 0x00}, + {0x8e, 0x00}, + {0xc0, 0x28}, + {0xc1, 0x1e}, + {0xc2, 0x01}, + {0xc3, 0x01}, +}; +static const u8 sensor_start_qvga_gbrg_772x[][2] = { + {0x12, 0x41}, + {0x17, 0x3f}, + {0x18, 0x50}, + {0x19, 0x03}, + {0x1a, 0x78}, + {0x29, 0x50}, + {0x2c, 0x78}, + {0x65, 0x2f}, + {0x67, 0x02}, }; static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) @@ -1316,25 +1390,33 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int mode; - static const struct reg_array bridge_start[NSENSORS][2] = { + static const struct reg_array bridge_start[NSENSORS][4] = { [SENSOR_OV767x] = {{bridge_start_qvga_767x, ARRAY_SIZE(bridge_start_qvga_767x)}, {bridge_start_vga_767x, ARRAY_SIZE(bridge_start_vga_767x)}}, - [SENSOR_OV772x] = {{bridge_start_qvga_772x, - ARRAY_SIZE(bridge_start_qvga_772x)}, - {bridge_start_vga_772x, - ARRAY_SIZE(bridge_start_vga_772x)}}, + [SENSOR_OV772x] = {{bridge_start_qvga_yuyv_772x, + ARRAY_SIZE(bridge_start_qvga_yuyv_772x)}, + {bridge_start_vga_yuyv_772x, + ARRAY_SIZE(bridge_start_vga_yuyv_772x)}, + {bridge_start_qvga_gbrg_772x, + ARRAY_SIZE(bridge_start_qvga_gbrg_772x)}, + {bridge_start_vga_gbrg_772x, + ARRAY_SIZE(bridge_start_vga_gbrg_772x)} }, }; - static const struct reg_array sensor_start[NSENSORS][2] = { + static const struct reg_array sensor_start[NSENSORS][4] = { [SENSOR_OV767x] = {{sensor_start_qvga_767x, ARRAY_SIZE(sensor_start_qvga_767x)}, {sensor_start_vga_767x, ARRAY_SIZE(sensor_start_vga_767x)}}, - [SENSOR_OV772x] = {{sensor_start_qvga_772x, - ARRAY_SIZE(sensor_start_qvga_772x)}, - {sensor_start_vga_772x, - ARRAY_SIZE(sensor_start_vga_772x)}}, + [SENSOR_OV772x] = {{sensor_start_qvga_yuyv_772x, + ARRAY_SIZE(sensor_start_qvga_yuyv_772x)}, + {sensor_start_vga_yuyv_772x, + ARRAY_SIZE(sensor_start_vga_yuyv_772x)}, + {sensor_start_qvga_gbrg_772x, + ARRAY_SIZE(sensor_start_qvga_gbrg_772x)}, + {sensor_start_vga_gbrg_772x, + ARRAY_SIZE(sensor_start_vga_gbrg_772x)} }, }; /* (from ms-win trace) */ @@ -1440,10 +1522,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* If this packet is marked as EOF, end the frame */ } else if (data[1] & UVC_STREAM_EOF) { sd->last_pts = 0; - if (gspca_dev->pixfmt.pixelformat == V4L2_PIX_FMT_YUYV + if (gspca_dev->pixfmt.pixelformat != V4L2_PIX_FMT_JPEG && gspca_dev->image_len + len - 12 != - gspca_dev->pixfmt.width * - gspca_dev->pixfmt.height * 2) { + gspca_dev->pixfmt.sizeimage) { gspca_dbg(gspca_dev, D_PACK, "wrong sized frame\n"); goto discard; } -- cgit v1.2.3 From ee1845d1cb9f6e6c74cfce958ce51985bf2a631e Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 14 Dec 2018 11:40:29 -0500 Subject: media: gspca: ov534-ov722x: remove mode specific video data registers from bridge_init The video format, payload size, and frame size setup is video format and frame size specific. Those registers are overwritten during bridge_start anyway. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/ov534.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 5b73f7f58ae6..bc9d2eb5db30 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -462,15 +462,6 @@ static const u8 bridge_init_772x[][2] = { { 0x25, 0x42 }, { 0x21, 0xf0 }, - { 0x1c, 0x00 }, - { 0x1d, 0x40 }, - { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */ - { 0x1d, 0x00 }, /* payload size */ - - { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */ - { 0x1d, 0x58 }, /* frame size */ - { 0x1d, 0x00 }, /* frame size */ - { 0x1c, 0x0a }, { 0x1d, 0x08 }, /* turn on UVC header */ { 0x1d, 0x0e }, /* .. */ -- cgit v1.2.3 From c5550bb9502bf6ef2eb514eee5eec486fe1cfb5c Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 14 Dec 2018 11:40:30 -0500 Subject: media: gspca: ov534-ov722x: remove camera clock setup from bridge_init This register is later overwritten by set_frame_rate anyway. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/ov534.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index bc9d2eb5db30..23deeedd3279 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -465,8 +465,6 @@ static const u8 bridge_init_772x[][2] = { { 0x1c, 0x0a }, { 0x1d, 0x08 }, /* turn on UVC header */ { 0x1d, 0x0e }, /* .. */ - - { 0xe5, 0x04 }, }; static const u8 sensor_init_772x[][2] = { { 0x12, 0x80 }, -- cgit v1.2.3 From 530993347bae43648f4aca2966c37cd269af66b7 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 14 Dec 2018 11:40:31 -0500 Subject: media: gspca: ov534-ov772x: remove unnecessary COM3 initialization The COM3 register at address 0x0c already defaults to 0x10, the two bits COM3[7:6] are set according to V4L2 controls by sethvflip later. There is no need to set it multiple times during bridge initialization. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/ov534.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 23deeedd3279..02c90ad96b76 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -543,13 +543,10 @@ static const u8 sensor_init_772x[][2] = { { 0x8c, 0xe8 }, { 0x8d, 0x20 }, - { 0x0c, 0x90 }, - { 0x2b, 0x00 }, { 0x22, 0x7f }, { 0x23, 0x03 }, { 0x11, 0x01 }, - { 0x0c, 0xd0 }, { 0x64, 0xff }, { 0x0d, 0x41 }, @@ -557,7 +554,6 @@ static const u8 sensor_init_772x[][2] = { { 0x0e, 0xcd }, { 0xac, 0xbf }, { 0x8e, 0x00 }, /* De-noise threshold */ - { 0x0c, 0xd0 } }; static const u8 bridge_start_vga_yuyv_772x[][2] = { {0x88, 0x00}, -- cgit v1.2.3 From 50656bad786d001b294764e9f047c5d5b3e4db75 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 10 Jan 2019 11:56:09 -0500 Subject: media: v4l2-ctrl: Add control to enable h.264 constrained intra prediction Allow to enable h.264 constrained intra prediction (macroblocks using intra prediction modes are not allowed to use residual data and decoded samples of neighboring macroblocks coded using inter prediction modes). This control directly corresponds to the constrained_intra_pred_flag field in the h.264 picture parameter set. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 8c47d8f00429..50b56185c02e 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -825,6 +825,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers"; case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP: return "H264 Set QP Value for HC Layers"; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + return "H264 Constrained Intra Pred"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; -- cgit v1.2.3 From d034696cbe5a6e00f76ca4b7869c6cdef66aebd5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 10 Jan 2019 11:56:10 -0500 Subject: media: v4l2-ctrl: Add control for h.264 chroma qp offset Allow to add fixed quantization parameter offset between luma and chroma quantization parameters. This control directly corresponds to the chroma_qp_index_offset field of the h.264 picture parameter set. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 50b56185c02e..99308dac2daa 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -827,6 +827,7 @@ const char *v4l2_ctrl_get_name(u32 id) return "H264 Set QP Value for HC Layers"; case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: return "H264 Constrained Intra Pred"; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: return "H264 Chroma QP Index Offset"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; -- cgit v1.2.3 From 31489f6bdabf4fa96f354fe3520ea779bebc6ee7 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 10 Jan 2019 11:56:11 -0500 Subject: media: coda: Add control for h.264 constrained intra prediction Allow to enable constrained intra prediction in the h.264 encoder. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 4 +++- drivers/media/platform/coda/coda-common.c | 6 ++++++ drivers/media/platform/coda/coda.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 8e0194993a52..2998c869f79f 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1010,7 +1010,9 @@ static int coda_start_encoding(struct coda_ctx *ctx) CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | ((ctx->params.h264_slice_beta_offset_div2 & CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); + CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) | + (ctx->params.h264_constrained_intra_pred_flag << + CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET); coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); break; case V4L2_PIX_FMT_JPEG: diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 7518f01c48f7..f6c9273805bb 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1839,6 +1839,9 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: ctx->params.h264_disable_deblocking_filter_idc = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + ctx->params.h264_constrained_intra_pred_flag = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_H264_PROFILE: /* TODO: switch between baseline and constrained baseline */ if (ctx->inst_type == CODA_INST_ENCODER) @@ -1925,6 +1928,9 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, 0, 1, 1, + 0); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 31cea72f5b2a..f3d0cff4ef3a 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -118,6 +118,7 @@ struct coda_params { u8 h264_disable_deblocking_filter_idc; s8 h264_slice_alpha_c0_offset_div2; s8 h264_slice_beta_offset_div2; + bool h264_constrained_intra_pred_flag; u8 h264_profile_idc; u8 h264_level_idc; u8 mpeg4_intra_qp; -- cgit v1.2.3 From 3943f059823b6e15884387f31618b84826e924b3 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 10 Jan 2019 11:56:12 -0500 Subject: media: coda: Add control for h.264 chroma qp index offset Allow to set a fixed quantization parameter offset between luma and chroma in the h.264 encoder. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 4 +++- drivers/media/platform/coda/coda-common.c | 5 +++++ drivers/media/platform/coda/coda.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 2998c869f79f..88065b07149c 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1012,7 +1012,9 @@ static int coda_start_encoding(struct coda_ctx *ctx) CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) | (ctx->params.h264_constrained_intra_pred_flag << - CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET); + CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) | + (ctx->params.h264_chroma_qp_index_offset & + CODA_264PARAM_CHROMAQPOFFSET_MASK); coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); break; case V4L2_PIX_FMT_JPEG: diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index f6c9273805bb..390d1ce6ab32 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1842,6 +1842,9 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: ctx->params.h264_constrained_intra_pred_flag = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: + ctx->params.h264_chroma_qp_index_offset = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_H264_PROFILE: /* TODO: switch between baseline and constrained baseline */ if (ctx->inst_type == CODA_INST_ENCODER) @@ -1931,6 +1934,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, 0, 1, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index f3d0cff4ef3a..31c80bda2c0b 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -119,6 +119,7 @@ struct coda_params { s8 h264_slice_alpha_c0_offset_div2; s8 h264_slice_beta_offset_div2; bool h264_constrained_intra_pred_flag; + s8 h264_chroma_qp_index_offset; u8 h264_profile_idc; u8 h264_level_idc; u8 mpeg4_intra_qp; -- cgit v1.2.3 From c5ff0edb8e2270a75935c73217fb0de1abd2d910 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Mon, 14 Jan 2019 20:10:19 -0500 Subject: media: rcar-vin: Allow independent VIN link enablement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a block of code in rvin_group_link_notify() that prevents enabling a link to a VIN node if any entity in the media graph is in use. This prevents enabling a VIN link even if there is an in-use entity somewhere in the graph that is independent of the link's pipeline. For example, the code block will prevent enabling a link from the first rcar-csi2 receiver to a VIN node even if there is an enabled link somewhere far upstream on the second independent rcar-csi2 receiver pipeline. If this code block is meant to prevent modifying a link if any entity in the graph is actively involved in streaming (because modifying the CHSEL register fields can disrupt any/all running streams), then the entities stream counts should be checked rather than the use counts. (There is already such a check in __media_entity_setup_link() that verifies the stream_count of the link's source and sink entities are both zero, but that is insufficient, since there should be no running streams in the entire graph). Modify the code block to check the entity stream_count instead of the use_count (and elaborate on the comment). VIN node links can now be enabled even if there are other independent in-use entities that are not streaming. Fixes: c0cc5aef31 ("media: rcar-vin: add link notify for Gen3") Signed-off-by: Steve Longerbeam Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index b28e3ff191c2..594d80434004 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -131,9 +131,13 @@ static int rvin_group_link_notify(struct media_link *link, u32 flags, !is_media_entity_v4l2_video_device(link->sink->entity)) return 0; - /* If any entity is in use don't allow link changes. */ + /* + * Don't allow link changes if any entity in the graph is + * streaming, modifying the CHSEL register fields can disrupt + * running streams. + */ media_device_for_each_entity(entity, &group->mdev) - if (entity->use_count) + if (entity->stream_count) return -EBUSY; mutex_lock(&group->lock); -- cgit v1.2.3 From fc8c723852380b0f4349bb06cf553a6bba47462e Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:05 -0500 Subject: media: gpu: ipu-csi: Swap fields according to input/output field types The function ipu_csi_init_interface() was inverting the F-bit for NTSC case, in the CCIR_CODE_1/2 registers. The result being that for NTSC bottom-top field order, the CSI would swap fields and capture in top-bottom order. Instead, base field swap on the field order of the input to the CSI, and the field order of the requested output. If the input/output fields are sequential but different, swap fields, otherwise do not swap. This requires passing both the input and output mbus frame formats to ipu_csi_init_interface(). Move this code to a new private function ipu_csi_set_bt_interlaced_codes() that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and possibly interlaced BT.1120 in the future). When detecting input video standard from the input frame width/height, make sure to double height if input field type is alternate, since in that case input height only includes lines for one field. Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/gpu/ipu-v3/ipu-csi.c | 126 ++++++++++++++++++++---------- drivers/staging/media/imx/imx-media-csi.c | 7 +- 2 files changed, 86 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index aa0e30a2ba18..d1e575571a8d 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -325,12 +325,21 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code, return 0; } +/* translate alternate field mode based on given standard */ +static inline enum v4l2_field +ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std) +{ + return (field != V4L2_FIELD_ALTERNATE) ? field : + ((std & V4L2_STD_525_60) ? + V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB); +} + /* * Fill a CSI bus config struct from mbus_config and mbus_framefmt. */ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, - struct v4l2_mbus_config *mbus_cfg, - struct v4l2_mbus_framefmt *mbus_fmt) + const struct v4l2_mbus_config *mbus_cfg, + const struct v4l2_mbus_framefmt *mbus_fmt) { int ret; @@ -374,22 +383,76 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, return 0; } +static int +ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi, + const struct v4l2_mbus_framefmt *infmt, + const struct v4l2_mbus_framefmt *outfmt, + v4l2_std_id std) +{ + enum v4l2_field infield, outfield; + bool swap_fields; + + /* get translated field type of input and output */ + infield = ipu_csi_translate_field(infmt->field, std); + outfield = ipu_csi_translate_field(outfmt->field, std); + + /* + * Write the H-V-F codes the CSI will match against the + * incoming data for start/end of active and blanking + * field intervals. If input and output field types are + * sequential but not the same (one is SEQ_BT and the other + * is SEQ_TB), swap the F-bit so that the CSI will capture + * field 1 lines before field 0 lines. + */ + swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) && + V4L2_FIELD_IS_SEQUENTIAL(outfield) && + infield != outfield); + + if (!swap_fields) { + /* + * Field0BlankEnd = 110, Field0BlankStart = 010 + * Field0ActiveEnd = 100, Field0ActiveStart = 000 + * Field1BlankEnd = 111, Field1BlankStart = 011 + * Field1ActiveEnd = 101, Field1ActiveStart = 001 + */ + ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN, + CSI_CCIR_CODE_1); + ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2); + } else { + dev_dbg(csi->ipu->dev, "capture field swap\n"); + + /* same as above but with F-bit inverted */ + ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN, + CSI_CCIR_CODE_1); + ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2); + } + + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); + + return 0; +} + + int ipu_csi_init_interface(struct ipu_csi *csi, - struct v4l2_mbus_config *mbus_cfg, - struct v4l2_mbus_framefmt *mbus_fmt) + const struct v4l2_mbus_config *mbus_cfg, + const struct v4l2_mbus_framefmt *infmt, + const struct v4l2_mbus_framefmt *outfmt) { struct ipu_csi_bus_config cfg; unsigned long flags; u32 width, height, data = 0; + v4l2_std_id std; int ret; - ret = fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt); + ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt); if (ret < 0) return ret; /* set default sensor frame width and height */ - width = mbus_fmt->width; - height = mbus_fmt->height; + width = infmt->width; + height = infmt->height; + if (infmt->field == V4L2_FIELD_ALTERNATE) + height *= 2; /* Set the CSI_SENS_CONF register remaining fields */ data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT | @@ -416,42 +479,22 @@ int ipu_csi_init_interface(struct ipu_csi *csi, ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); break; case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: - if (mbus_fmt->width == 720 && mbus_fmt->height == 576) { - /* - * PAL case - * - * Field0BlankEnd = 0x6, Field0BlankStart = 0x2, - * Field0ActiveEnd = 0x4, Field0ActiveStart = 0 - * Field1BlankEnd = 0x7, Field1BlankStart = 0x3, - * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1 - */ - height = 625; /* framelines for PAL */ - - ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN, - CSI_CCIR_CODE_1); - ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2); - ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); - } else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) { - /* - * NTSC case - * - * Field0BlankEnd = 0x7, Field0BlankStart = 0x3, - * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1 - * Field1BlankEnd = 0x6, Field1BlankStart = 0x2, - * Field1ActiveEnd = 0x4, Field1ActiveStart = 0 - */ - height = 525; /* framelines for NTSC */ - - ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN, - CSI_CCIR_CODE_1); - ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2); - ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); + if (width == 720 && height == 480) { + std = V4L2_STD_NTSC; + height = 525; + } else if (width == 720 && height == 576) { + std = V4L2_STD_PAL; + height = 625; } else { dev_err(csi->ipu->dev, - "Unsupported CCIR656 interlaced video mode\n"); - spin_unlock_irqrestore(&csi->lock, flags); - return -EINVAL; + "Unsupported interlaced video mode\n"); + ret = -EINVAL; + goto out_unlock; } + + ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std); + if (ret) + goto out_unlock; break; case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: @@ -476,9 +519,10 @@ int ipu_csi_init_interface(struct ipu_csi *csi, dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n", ipu_csi_read(csi, CSI_ACT_FRM_SIZE)); +out_unlock: spin_unlock_irqrestore(&csi->lock, flags); - return 0; + return ret; } EXPORT_SYMBOL_GPL(ipu_csi_init_interface); diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 4223f8d418ae..c2a8d9cd31b7 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -679,12 +679,7 @@ static int csi_setup(struct csi_priv *priv) priv->upstream_ep.bus.parallel.flags : priv->upstream_ep.bus.mipi_csi2.flags; - /* - * we need to pass input frame to CSI interface, but - * with translated field type from output format - */ if_fmt = *infmt; - if_fmt.field = outfmt->field; crop = priv->crop; /* @@ -702,7 +697,7 @@ static int csi_setup(struct csi_priv *priv) priv->crop.width == 2 * priv->compose.width, priv->crop.height == 2 * priv->compose.height); - ipu_csi_init_interface(priv->csi, &mbus_cfg, &if_fmt); + ipu_csi_init_interface(priv->csi, &mbus_cfg, &if_fmt, outfmt); ipu_csi_set_dest(priv->csi, priv->dest); -- cgit v1.2.3 From 9b5c8d5ffb20cc4f4b1476cb1ad57e0f9b934788 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:06 -0500 Subject: media: gpu: ipu-v3: Add planar support to interlaced scan To support interlaced scan with planar formats, cpmem SLUV must be programmed with the correct chroma line stride. For full and partial planar 4:2:2 (YUV422P, NV16), chroma line stride must be doubled. For full and partial planar 4:2:0 (YUV420, YVU420, NV12), chroma line stride must _not_ be doubled, since a single chroma line is shared by two luma lines. Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/gpu/ipu-v3/ipu-cpmem.c | 26 ++++++++++++++++++++++++-- drivers/staging/media/imx/imx-ic-prpencvf.c | 3 ++- drivers/staging/media/imx/imx-media-csi.c | 3 ++- 3 files changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index 163fadb8a33a..d047a6867c59 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -277,9 +277,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off) } EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset); -void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride) +void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride, + u32 pixelformat) { - u32 ilo, sly; + u32 ilo, sly, sluv; if (stride < 0) { stride = -stride; @@ -290,9 +291,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride) sly = (stride * 2) - 1; + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + sluv = stride / 2 - 1; + break; + case V4L2_PIX_FMT_NV12: + sluv = stride - 1; + break; + case V4L2_PIX_FMT_YUV422P: + sluv = stride - 1; + break; + case V4L2_PIX_FMT_NV16: + sluv = stride * 2 - 1; + break; + default: + sluv = 0; + break; + } + ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1); ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo); ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly); + if (sluv) + ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv); }; EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan); diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 28f41caba05d..af7224846bd5 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -412,7 +412,8 @@ static int prp_setup_channel(struct prp_priv *priv, if (image.pix.field == V4L2_FIELD_NONE && V4L2_FIELD_HAS_BOTH(infmt->field) && channel == priv->out_ch) - ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline); + ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline, + image.pix.pixelformat); ret = ipu_ic_task_idma_init(priv->ic, channel, image.pix.width, image.pix.height, diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index c2a8d9cd31b7..da4808348845 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -512,7 +512,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) if (image.pix.field == V4L2_FIELD_NONE && V4L2_FIELD_HAS_BOTH(infmt->field)) ipu_cpmem_interlaced_scan(priv->idmac_ch, - image.pix.bytesperline); + image.pix.bytesperline, + image.pix.pixelformat); ipu_idmac_set_double_buffer(priv->idmac_ch, true); -- cgit v1.2.3 From d969291d8479dcbb7f093738279527d14cdb756c Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:07 -0500 Subject: media: imx: Fix field negotiation IDMAC interlaced scan, a.k.a. interweave, should be enabled in the IDMAC output channels only if the IDMAC output pad field type is 'seq-bt' or 'seq-tb', and field type at the capture interface is 'interlaced*'. V4L2_FIELD_HAS_BOTH() macro should not be used on the input to determine enabling interlaced/interweave scan. That macro includes the 'interlaced' field types, and in those cases the data is already interweaved with top/bottom field lines. The CSI will capture whole frames when the source specifies alternate field mode. So the CSI also enables interweave for alternate input field type and the field type at capture interface is interlaced. Fix the logic for setting field type in try_fmt in CSI entity. The behavior should be: - No restrictions on field type at sink pad. - At the output pads, allow sequential fields in TB order, if the sink pad field type is sequential or alternate. Otherwise passthrough the field type from sink to source pad. Move this logic to new function csi_try_field(). These changes result in the following allowed field transformations from CSI sink -> source pads (all other field types at sink are passed through to source): seq-tb -> seq-tb seq-bt -> seq-tb alternate -> seq-tb In a future patch, the CSI sink -> source will allow: seq-tb -> seq-bt seq-bt -> seq-bt alternate -> seq-bt This will require supporting interweave with top/bottom line swapping. Until then seq-bt is not allowed at the CSI source pad because there is no way to swap top/bottom lines when interweaving to INTERLACED_BT -- note that despite the name, INTERLACED_BT is top-bottom order in memory. The BT in this case refers to field dominance: the bottom lines are older in time than the top lines. The capture interface device allows selecting IDMAC interweave by choosing INTERLACED_TB if the CSI/PRPENCVF source pad is seq-tb and INTERLACED_BT if the source pad is seq-bt (for future support of seq-bt). Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-ic-prpencvf.c | 21 ++++++--- drivers/staging/media/imx/imx-media-capture.c | 14 ++++++ drivers/staging/media/imx/imx-media-csi.c | 64 ++++++++++++++++++++------- 3 files changed, 76 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index af7224846bd5..1a03d4c9d7b8 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -354,12 +354,13 @@ static int prp_setup_channel(struct prp_priv *priv, { struct imx_media_video_dev *vdev = priv->vdev; const struct imx_media_pixfmt *outcc; - struct v4l2_mbus_framefmt *infmt; + struct v4l2_mbus_framefmt *outfmt; unsigned int burst_size; struct ipu_image image; + bool interweave; int ret; - infmt = &priv->format_mbus[PRPENCVF_SINK_PAD]; + outfmt = &priv->format_mbus[PRPENCVF_SRC_PAD]; outcc = vdev->cc; ipu_cpmem_zero(channel); @@ -369,6 +370,15 @@ static int prp_setup_channel(struct prp_priv *priv, image.rect.width = image.pix.width; image.rect.height = image.pix.height; + /* + * If the field type at capture interface is interlaced, and + * the output IDMAC pad is sequential, enable interweave at + * the IDMAC output channel. + */ + interweave = V4L2_FIELD_IS_INTERLACED(image.pix.field) && + V4L2_FIELD_IS_SEQUENTIAL(outfmt->field) && + channel == priv->out_ch; + if (rot_swap_width_height) { swap(image.pix.width, image.pix.height); swap(image.rect.width, image.rect.height); @@ -409,9 +419,7 @@ static int prp_setup_channel(struct prp_priv *priv, if (rot_mode) ipu_cpmem_set_rotation(channel, rot_mode); - if (image.pix.field == V4L2_FIELD_NONE && - V4L2_FIELD_HAS_BOTH(infmt->field) && - channel == priv->out_ch) + if (interweave) ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline, image.pix.pixelformat); @@ -839,8 +847,7 @@ static void prp_try_fmt(struct prp_priv *priv, infmt = __prp_get_fmt(priv, cfg, PRPENCVF_SINK_PAD, sdformat->which); if (sdformat->pad == PRPENCVF_SRC_PAD) { - if (sdformat->format.field != V4L2_FIELD_NONE) - sdformat->format.field = infmt->field; + sdformat->format.field = infmt->field; prp_bound_align_output(&sdformat->format, infmt, priv->rot_mode); diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index b37e1186eb2f..01ec9443de55 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -239,6 +239,20 @@ static int capture_try_fmt_vid_cap(struct file *file, void *fh, cc = cc_src; } + /* allow IDMAC interweave but enforce field order from source */ + if (V4L2_FIELD_IS_INTERLACED(f->fmt.pix.field)) { + switch (fmt_src.format.field) { + case V4L2_FIELD_SEQ_TB: + fmt_src.format.field = V4L2_FIELD_INTERLACED_TB; + break; + case V4L2_FIELD_SEQ_BT: + fmt_src.format.field = V4L2_FIELD_INTERLACED_BT; + break; + default: + break; + } + } + imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, &fmt_src.format, cc); return 0; diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index da4808348845..e3a4f39dbf73 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -398,16 +398,18 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) struct imx_media_video_dev *vdev = priv->vdev; const struct imx_media_pixfmt *incc; struct v4l2_mbus_framefmt *infmt; + struct v4l2_mbus_framefmt *outfmt; + bool passthrough, interweave; struct ipu_image image; u32 passthrough_bits; u32 passthrough_cycles; dma_addr_t phys[2]; - bool passthrough; u32 burst_size; int ret; infmt = &priv->format_mbus[CSI_SINK_PAD]; incc = priv->cc[CSI_SINK_PAD]; + outfmt = &priv->format_mbus[CSI_SRC_PAD_IDMAC]; ipu_cpmem_zero(priv->idmac_ch); @@ -424,6 +426,14 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) passthrough = requires_passthrough(&priv->upstream_ep, infmt, incc); passthrough_cycles = 1; + /* + * If the field type at capture interface is interlaced, and + * the output IDMAC pad is sequential, enable interweave at + * the IDMAC output channel. + */ + interweave = V4L2_FIELD_IS_INTERLACED(image.pix.field) && + V4L2_FIELD_IS_SEQUENTIAL(outfmt->field); + switch (image.pix.pixelformat) { case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: @@ -509,8 +519,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) ipu_smfc_set_burstsize(priv->smfc, burst_size); - if (image.pix.field == V4L2_FIELD_NONE && - V4L2_FIELD_HAS_BOTH(infmt->field)) + if (interweave) ipu_cpmem_interlaced_scan(priv->idmac_ch, image.pix.bytesperline, image.pix.pixelformat); @@ -1304,6 +1313,38 @@ out: return ret; } +static void csi_try_field(struct csi_priv *priv, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *sdformat) +{ + struct v4l2_mbus_framefmt *infmt = + __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which); + + /* no restrictions on sink pad field type */ + if (sdformat->pad == CSI_SINK_PAD) + return; + + switch (infmt->field) { + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_ALTERNATE: + /* + * If the sink is sequential or alternating fields, + * allow only SEQ_TB at the source. + * + * This driver does not support alternate field mode, and + * the CSI captures a whole frame, so the CSI never presents + * alternate mode at its source pads. + */ + sdformat->format.field = V4L2_FIELD_SEQ_TB; + break; + default: + /* Passthrough for all other input field types */ + sdformat->format.field = infmt->field; + break; + } +} + static void csi_try_fmt(struct csi_priv *priv, struct v4l2_fwnode_endpoint *upstream_ep, struct v4l2_subdev_pad_config *cfg, @@ -1343,25 +1384,14 @@ static void csi_try_fmt(struct csi_priv *priv, } } - if (sdformat->pad == CSI_SRC_PAD_DIRECT || - sdformat->format.field != V4L2_FIELD_NONE) - sdformat->format.field = infmt->field; - - /* - * translate V4L2_FIELD_ALTERNATE to SEQ_TB or SEQ_BT - * depending on input height (assume NTSC top-bottom - * order if 480 lines, otherwise PAL bottom-top order). - */ - if (sdformat->format.field == V4L2_FIELD_ALTERNATE) { - sdformat->format.field = (infmt->height == 480) ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT; - } + csi_try_field(priv, cfg, sdformat); /* propagate colorimetry from sink */ sdformat->format.colorspace = infmt->colorspace; sdformat->format.xfer_func = infmt->xfer_func; sdformat->format.quantization = infmt->quantization; sdformat->format.ycbcr_enc = infmt->ycbcr_enc; + break; case CSI_SINK_PAD: v4l_bound_align_image(&sdformat->format.width, MIN_W, MAX_W, @@ -1389,6 +1419,8 @@ static void csi_try_fmt(struct csi_priv *priv, sdformat->format.code = (*cc)->codes[0]; } + csi_try_field(priv, cfg, sdformat); + imx_media_fill_default_mbus_fields( &sdformat->format, infmt, priv->active_output_pad == CSI_SRC_PAD_DIRECT); -- cgit v1.2.3 From 2a87c0c9344489afe6c7a613d883a041a5441bcd Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:08 -0500 Subject: media: imx-csi: Double crop height for alternate fields at sink If the incoming sink field type is alternate, the reset crop height and crop height bounds must be set to twice the incoming height, because in alternate field mode, upstream will report only the lines for a single field, and the CSI captures the whole frame. Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-csi.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index e3a4f39dbf73..10945cbdbd71 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -1142,6 +1142,8 @@ static void csi_try_crop(struct csi_priv *priv, struct v4l2_mbus_framefmt *infmt, struct v4l2_fwnode_endpoint *upstream_ep) { + u32 in_height; + crop->width = min_t(__u32, infmt->width, crop->width); if (crop->left + crop->width > infmt->width) crop->left = infmt->width - crop->width; @@ -1149,6 +1151,10 @@ static void csi_try_crop(struct csi_priv *priv, crop->left &= ~0x3; crop->width &= ~0x7; + in_height = infmt->height; + if (infmt->field == V4L2_FIELD_ALTERNATE) + in_height *= 2; + /* * FIXME: not sure why yet, but on interlaced bt.656, * changing the vertical cropping causes loss of vertical @@ -1158,12 +1164,12 @@ static void csi_try_crop(struct csi_priv *priv, if (upstream_ep->bus_type == V4L2_MBUS_BT656 && (V4L2_FIELD_HAS_BOTH(infmt->field) || infmt->field == V4L2_FIELD_ALTERNATE)) { - crop->height = infmt->height; - crop->top = (infmt->height == 480) ? 2 : 0; + crop->height = in_height; + crop->top = (in_height == 480) ? 2 : 0; } else { - crop->height = min_t(__u32, infmt->height, crop->height); - if (crop->top + crop->height > infmt->height) - crop->top = infmt->height - crop->height; + crop->height = min_t(__u32, in_height, crop->height); + if (crop->top + crop->height > in_height) + crop->top = in_height - crop->height; } } @@ -1403,6 +1409,8 @@ static void csi_try_fmt(struct csi_priv *priv, crop->top = 0; crop->width = sdformat->format.width; crop->height = sdformat->format.height; + if (sdformat->format.field == V4L2_FIELD_ALTERNATE) + crop->height *= 2; csi_try_crop(priv, crop, cfg, &sdformat->format, upstream_ep); compose->left = 0; compose->top = 0; @@ -1530,6 +1538,8 @@ static int csi_get_selection(struct v4l2_subdev *sd, sel->r.top = 0; sel->r.width = infmt->width; sel->r.height = infmt->height; + if (infmt->field == V4L2_FIELD_ALTERNATE) + sel->r.height *= 2; break; case V4L2_SEL_TGT_CROP: sel->r = *crop; -- cgit v1.2.3 From bc11dd6699960c241dc067d55aa4be37b722afd5 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:09 -0500 Subject: media: imx: interweave and odd-chroma-row skip are incompatible If IDMAC interweaving is enabled in a write channel, the channel must write the odd chroma rows for 4:2:0 formats. Skipping writing the odd chroma rows produces corrupted captured 4:2:0 images when interweave is enabled. Reported-by: Krzysztof Ha?asa Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-ic-prpencvf.c | 9 +++++++-- drivers/staging/media/imx/imx-media-csi.c | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 1a03d4c9d7b8..cf76b0432371 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -391,12 +391,17 @@ static int prp_setup_channel(struct prp_priv *priv, image.phys0 = addr0; image.phys1 = addr1; - if (channel == priv->out_ch || channel == priv->rot_out_ch) { + /* + * Skip writing U and V components to odd rows in the output + * channels for planar 4:2:0 (but not when enabling IDMAC + * interweaving, they are incompatible). + */ + if (!interweave && (channel == priv->out_ch || + channel == priv->rot_out_ch)) { switch (image.pix.pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_NV12: - /* Skip writing U and V components to odd rows */ ipu_cpmem_skip_odd_chroma_rows(channel); break; } diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 10945cbdbd71..604d0bd24389 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -457,8 +457,12 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) ((image.pix.width & 0x1f) ? ((image.pix.width & 0xf) ? 8 : 16) : 32) : 64; passthrough_bits = 16; - /* Skip writing U and V components to odd rows */ - ipu_cpmem_skip_odd_chroma_rows(priv->idmac_ch); + /* + * Skip writing U and V components to odd rows (but not + * when enabling IDMAC interweaving, they are incompatible). + */ + if (!interweave) + ipu_cpmem_skip_odd_chroma_rows(priv->idmac_ch); break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: -- cgit v1.2.3 From 792f061b9f752f28fdaa1986b43f109689dc1416 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:10 -0500 Subject: media: imx-csi: Allow skipping odd chroma rows for YVU420 Skip writing U/V components to odd rows for YVU420 in addition to YUV420 and NV12. Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-csi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 604d0bd24389..6f1e11b8a7cb 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -452,6 +452,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) passthrough_bits = 16; break; case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_NV12: burst_size = (image.pix.width & 0x3f) ? ((image.pix.width & 0x1f) ? -- cgit v1.2.3 From 6e537b58de772cfc89d4fbd0cddd0c1de5f93822 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:11 -0500 Subject: media: imx: vdic: rely on VDIC for correct field order prepare_vdi_in_buffers() was setting up the dma pointers as if the VDIC is always programmed to receive the fields in bottom-top order, i.e. as if ipu_vdi_set_field_order() only programs BT order in the VDIC. But that's not true, ipu_vdi_set_field_order() is working correctly. So fix prepare_vdi_in_buffers() to give the VDIC the fields in whatever order they were received by the video source, and rely on the VDIC to sort out which is top and which is bottom. Signed-off-by: Steve Longerbeam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-vdic.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index 482250d47e7c..4a890714193e 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -219,26 +219,18 @@ static void __maybe_unused prepare_vdi_in_buffers(struct vdic_priv *priv, switch (priv->fieldtype) { case V4L2_FIELD_SEQ_TB: - prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0); - curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + fs; - next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); - break; case V4L2_FIELD_SEQ_BT: prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0) + fs; curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + fs; break; + case V4L2_FIELD_INTERLACED_TB: case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_INTERLACED: prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0) + is; curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + is; break; - default: - /* assume V4L2_FIELD_INTERLACED_TB */ - prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0); - curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + is; - next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); - break; } ipu_cpmem_set_buffer(priv->vdi_in_ch_p, 0, prev_phys); -- cgit v1.2.3 From ab2f05cdb15421c1e57d3345852f6fb1405e3398 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:12 -0500 Subject: media: imx-csi: Move crop/compose reset after filling default mbus fields If caller passes un-initialized field type V4L2_FIELD_ANY to CSI sink pad, the reset CSI crop window would not be correct, because the crop window depends on a valid input field type. To fix move the reset of crop and compose windows to after the call to imx_media_fill_default_mbus_fields(). Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-csi.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 6f1e11b8a7cb..8537ecb7dd17 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -1409,19 +1409,6 @@ static void csi_try_fmt(struct csi_priv *priv, W_ALIGN, &sdformat->format.height, MIN_H, MAX_H, H_ALIGN, S_ALIGN); - /* Reset crop and compose rectangles */ - crop->left = 0; - crop->top = 0; - crop->width = sdformat->format.width; - crop->height = sdformat->format.height; - if (sdformat->format.field == V4L2_FIELD_ALTERNATE) - crop->height *= 2; - csi_try_crop(priv, crop, cfg, &sdformat->format, upstream_ep); - compose->left = 0; - compose->top = 0; - compose->width = crop->width; - compose->height = crop->height; - *cc = imx_media_find_mbus_format(sdformat->format.code, CS_SEL_ANY, true); if (!*cc) { @@ -1437,6 +1424,20 @@ static void csi_try_fmt(struct csi_priv *priv, imx_media_fill_default_mbus_fields( &sdformat->format, infmt, priv->active_output_pad == CSI_SRC_PAD_DIRECT); + + /* Reset crop and compose rectangles */ + crop->left = 0; + crop->top = 0; + crop->width = sdformat->format.width; + crop->height = sdformat->format.height; + if (sdformat->format.field == V4L2_FIELD_ALTERNATE) + crop->height *= 2; + csi_try_crop(priv, crop, cfg, &sdformat->format, upstream_ep); + compose->left = 0; + compose->top = 0; + compose->width = crop->width; + compose->height = crop->height; + break; } } -- cgit v1.2.3 From 3c6640a6065fe77691e88ae135f45be6826acf0a Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 9 Jan 2019 13:30:13 -0500 Subject: media: imx: Allow interweave with top/bottom lines swapped Allow sequential->interlaced interweaving but with top/bottom lines swapped to the output buffer. This can be accomplished by adding one line length to IDMAC output channel address, with a negative line length for the interlace offset. This is to allow the seq-bt -> interlaced-bt transformation, where bottom lines are still dominant (older in time) but with top lines first in the interweaved output buffer. With this support, the CSI can now allow seq-bt at its source pads, e.g. the following transformations are allowed in CSI from sink to source: seq-tb -> seq-bt seq-bt -> seq-bt alternate -> seq-bt Suggested-by: Philipp Zabel Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-ic-prpencvf.c | 25 +++++++++++++----- drivers/staging/media/imx/imx-media-csi.c | 40 +++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index cf76b0432371..33ada6612fee 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -106,6 +106,7 @@ struct prp_priv { u32 frame_sequence; /* frame sequence counter */ bool last_eof; /* waiting for last EOF at stream off */ bool nfb4eof; /* NFB4EOF encountered during streaming */ + bool interweave_swap; /* swap top/bottom lines when interweaving */ struct completion last_eof_comp; }; @@ -235,6 +236,9 @@ static void prp_vb2_buf_done(struct prp_priv *priv, struct ipuv3_channel *ch) if (ipu_idmac_buffer_is_ready(ch, priv->ipu_buf_num)) ipu_idmac_clear_buffer(ch, priv->ipu_buf_num); + if (priv->interweave_swap && ch == priv->out_ch) + phys += vdev->fmt.fmt.pix.bytesperline; + ipu_cpmem_set_buffer(ch, priv->ipu_buf_num, phys); } @@ -376,8 +380,9 @@ static int prp_setup_channel(struct prp_priv *priv, * the IDMAC output channel. */ interweave = V4L2_FIELD_IS_INTERLACED(image.pix.field) && - V4L2_FIELD_IS_SEQUENTIAL(outfmt->field) && - channel == priv->out_ch; + V4L2_FIELD_IS_SEQUENTIAL(outfmt->field); + priv->interweave_swap = interweave && + image.pix.field == V4L2_FIELD_INTERLACED_BT; if (rot_swap_width_height) { swap(image.pix.width, image.pix.height); @@ -388,6 +393,11 @@ static int prp_setup_channel(struct prp_priv *priv, (image.pix.width * outcc->bpp) >> 3; } + if (priv->interweave_swap && channel == priv->out_ch) { + /* start interweave scan at 1st top line (2nd line) */ + image.rect.top = 1; + } + image.phys0 = addr0; image.phys1 = addr1; @@ -396,8 +406,8 @@ static int prp_setup_channel(struct prp_priv *priv, * channels for planar 4:2:0 (but not when enabling IDMAC * interweaving, they are incompatible). */ - if (!interweave && (channel == priv->out_ch || - channel == priv->rot_out_ch)) { + if ((channel == priv->out_ch && !interweave) || + channel == priv->rot_out_ch) { switch (image.pix.pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: @@ -424,8 +434,11 @@ static int prp_setup_channel(struct prp_priv *priv, if (rot_mode) ipu_cpmem_set_rotation(channel, rot_mode); - if (interweave) - ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline, + if (interweave && channel == priv->out_ch) + ipu_cpmem_interlaced_scan(channel, + priv->interweave_swap ? + -image.pix.bytesperline : + image.pix.bytesperline, image.pix.pixelformat); ret = ipu_ic_task_idma_init(priv->ic, channel, diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 8537ecb7dd17..555aa45e02e3 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -114,6 +114,7 @@ struct csi_priv { u32 frame_sequence; /* frame sequence counter */ bool last_eof; /* waiting for last EOF at stream off */ bool nfb4eof; /* NFB4EOF encountered during streaming */ + bool interweave_swap; /* swap top/bottom lines when interweaving */ struct completion last_eof_comp; }; @@ -286,6 +287,9 @@ static void csi_vb2_buf_done(struct csi_priv *priv) if (ipu_idmac_buffer_is_ready(priv->idmac_ch, priv->ipu_buf_num)) ipu_idmac_clear_buffer(priv->idmac_ch, priv->ipu_buf_num); + if (priv->interweave_swap) + phys += vdev->fmt.fmt.pix.bytesperline; + ipu_cpmem_set_buffer(priv->idmac_ch, priv->ipu_buf_num, phys); } @@ -433,6 +437,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) */ interweave = V4L2_FIELD_IS_INTERLACED(image.pix.field) && V4L2_FIELD_IS_SEQUENTIAL(outfmt->field); + priv->interweave_swap = interweave && + image.pix.field == V4L2_FIELD_INTERLACED_BT; switch (image.pix.pixelformat) { case V4L2_PIX_FMT_SBGGR8: @@ -486,6 +492,12 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) } if (passthrough) { + if (priv->interweave_swap) { + /* start interweave scan at 1st top line (2nd line) */ + image.phys0 += image.pix.bytesperline; + image.phys1 += image.pix.bytesperline; + } + ipu_cpmem_set_resolution(priv->idmac_ch, image.rect.width * passthrough_cycles, image.rect.height); @@ -495,6 +507,11 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) ipu_cpmem_set_format_passthrough(priv->idmac_ch, passthrough_bits); } else { + if (priv->interweave_swap) { + /* start interweave scan at 1st top line (2nd line) */ + image.rect.top = 1; + } + ret = ipu_cpmem_set_image(priv->idmac_ch, &image); if (ret) goto unsetup_vb2; @@ -526,6 +543,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) if (interweave) ipu_cpmem_interlaced_scan(priv->idmac_ch, + priv->interweave_swap ? + -image.pix.bytesperline : image.pix.bytesperline, image.pix.pixelformat); @@ -1338,16 +1357,27 @@ static void csi_try_field(struct csi_priv *priv, switch (infmt->field) { case V4L2_FIELD_SEQ_TB: case V4L2_FIELD_SEQ_BT: + /* + * If the user requests sequential at the source pad, + * allow it (along with possibly inverting field order). + * Otherwise passthrough the field type. + */ + if (!V4L2_FIELD_IS_SEQUENTIAL(sdformat->format.field)) + sdformat->format.field = infmt->field; + break; case V4L2_FIELD_ALTERNATE: /* - * If the sink is sequential or alternating fields, - * allow only SEQ_TB at the source. - * * This driver does not support alternate field mode, and * the CSI captures a whole frame, so the CSI never presents - * alternate mode at its source pads. + * alternate mode at its source pads. If user has not + * already requested sequential, translate ALTERNATE at + * sink pad to SEQ_TB or SEQ_BT at the source pad depending + * on input height (assume NTSC BT order if 480 total active + * frame lines, otherwise PAL TB order). */ - sdformat->format.field = V4L2_FIELD_SEQ_TB; + if (!V4L2_FIELD_IS_SEQUENTIAL(sdformat->format.field)) + sdformat->format.field = (infmt->height == 480 / 2) ? + V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB; break; default: /* Passthrough for all other input field types */ -- cgit v1.2.3 From 2431c4f5b46c32c4ac495456b1ef4ce59c0bb85d Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 20 Dec 2018 15:13:20 +0100 Subject: mtd: Implement mtd_{read,write}() as wrappers around mtd_{read,write}_oob() mtd_{read,write}_oob() already take care of checking the params and calling ->_{read,write}() or ->_{read,write}_oob() based on the request and the operations supported by the MTD device. No need to duplicate the logic, we can simply implement mtd_{read,write}() as wrappers around mtd_{read,write}_oob(). Signed-off-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 75 +++++++++++++++++---------------------------------- 1 file changed, 24 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 21e3cdc04036..d5a7fc6ea3f3 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -559,6 +559,14 @@ int add_mtd_device(struct mtd_info *mtd) BUG_ON(mtd->writesize == 0); + /* + * MTD drivers should implement ->_{write,read}() or + * ->_{write,read}_oob(), but not both. + */ + if (WARN_ON((mtd->_write && mtd->_write_oob) || + (mtd->_read && mtd->_read_oob))) + return -EINVAL; + if (WARN_ON((!mtd->erasesize || !mtd->_erase) && !(mtd->flags & MTD_NO_ERASE))) return -EINVAL; @@ -1089,67 +1097,32 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area); int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - int ret_code; - *retlen = 0; - if (from < 0 || from >= mtd->size || len > mtd->size - from) - return -EINVAL; - if (!len) - return 0; + struct mtd_oob_ops ops = { + .len = len, + .datbuf = buf, + }; + int ret; - ledtrig_mtd_activity(); - /* - * In the absence of an error, drivers return a non-negative integer - * representing the maximum number of bitflips that were corrected on - * any one ecc region (if applicable; zero otherwise). - */ - if (mtd->_read) { - ret_code = mtd->_read(mtd, from, len, retlen, buf); - } else if (mtd->_read_oob) { - struct mtd_oob_ops ops = { - .len = len, - .datbuf = buf, - }; - - ret_code = mtd->_read_oob(mtd, from, &ops); - *retlen = ops.retlen; - } else { - return -ENOTSUPP; - } + ret = mtd_read_oob(mtd, from, &ops); + *retlen = ops.retlen; - if (unlikely(ret_code < 0)) - return ret_code; - if (mtd->ecc_strength == 0) - return 0; /* device lacks ecc */ - return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0; + return ret; } EXPORT_SYMBOL_GPL(mtd_read); int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - *retlen = 0; - if (to < 0 || to >= mtd->size || len > mtd->size - to) - return -EINVAL; - if ((!mtd->_write && !mtd->_write_oob) || - !(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - if (!len) - return 0; - ledtrig_mtd_activity(); - - if (!mtd->_write) { - struct mtd_oob_ops ops = { - .len = len, - .datbuf = (u8 *)buf, - }; - int ret; + struct mtd_oob_ops ops = { + .len = len, + .datbuf = (u8 *)buf, + }; + int ret; - ret = mtd->_write_oob(mtd, to, &ops); - *retlen = ops.retlen; - return ret; - } + ret = mtd_write_oob(mtd, to, &ops); + *retlen = ops.retlen; - return mtd->_write(mtd, to, len, retlen, buf); + return ret; } EXPORT_SYMBOL_GPL(mtd_write); -- cgit v1.2.3 From 8e1f456129e61371fb190c71ea182a9f6e21282e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 9 Jan 2019 15:44:46 +0100 Subject: leds: Add helper for getting default pattern from Device Tree Multiple LED triggers might need to access default pattern so add a helper for that. Signed-off-by: Krzysztof Kozlowski Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- drivers/leds/led-core.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index ede4fa0ac2cc..e3da7c03da1b 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include "leds.h" DECLARE_RWSEM(leds_list_lock); @@ -310,6 +312,34 @@ int led_update_brightness(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_update_brightness); +u32 *led_get_default_pattern(struct led_classdev *led_cdev, unsigned int *size) +{ + struct device_node *np = dev_of_node(led_cdev->dev); + u32 *pattern; + int count; + + if (!np) + return NULL; + + count = of_property_count_u32_elems(np, "led-pattern"); + if (count < 0) + return NULL; + + pattern = kcalloc(count, sizeof(*pattern), GFP_KERNEL); + if (!pattern) + return NULL; + + if (of_property_read_u32_array(np, "led-pattern", pattern, count)) { + kfree(pattern); + return NULL; + } + + *size = count; + + return pattern; +} +EXPORT_SYMBOL_GPL(led_get_default_pattern); + /* Caller must ensure led_cdev->led_access held */ void led_sysfs_disable(struct led_classdev *led_cdev) { -- cgit v1.2.3 From aa6fd10481bdb1af2d4a4b5975e23674e989cd81 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 9 Jan 2019 15:44:47 +0100 Subject: leds: trigger: pattern: Add pattern initialization from Device Tree Allow initialization of pattern used in pattern trigger from Device Tree property. This is especially useful for embedded systems where the pattern trigger would be used to indicate the process of boot status in a nice, user-friendly blinking way. This initialization pattern will be used till user-space is brought up and sets its own pattern, indicating the boot status is for example finished. Signed-off-by: Krzysztof Kozlowski Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- drivers/leds/trigger/ledtrig-pattern.c | 99 +++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c index 1870cf87afe1..718729c89440 100644 --- a/drivers/leds/trigger/ledtrig-pattern.c +++ b/drivers/leds/trigger/ledtrig-pattern.c @@ -220,22 +220,10 @@ out: return count; } -static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, - const char *buf, size_t count, - bool hw_pattern) +static int pattern_trig_store_patterns_string(struct pattern_trig_data *data, + const char *buf, size_t count) { - struct pattern_trig_data *data = led_cdev->trigger_data; - int ccount, cr, offset = 0, err = 0; - - mutex_lock(&data->lock); - - del_timer_sync(&data->timer); - - if (data->is_hw_pattern) - led_cdev->pattern_clear(led_cdev); - - data->is_hw_pattern = hw_pattern; - data->npatterns = 0; + int ccount, cr, offset = 0; while (offset < count - 1 && data->npatterns < MAX_PATTERNS) { cr = 0; @@ -244,14 +232,54 @@ static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, &data->patterns[data->npatterns].delta_t, &cr); if (ccount != 2) { data->npatterns = 0; - err = -EINVAL; - goto out; + return -EINVAL; } offset += cr; data->npatterns++; } + return 0; +} + +static int pattern_trig_store_patterns_int(struct pattern_trig_data *data, + const u32 *buf, size_t count) +{ + unsigned int i; + + for (i = 0; i < count; i += 2) { + data->patterns[data->npatterns].brightness = buf[i]; + data->patterns[data->npatterns].delta_t = buf[i + 1]; + data->npatterns++; + } + + return 0; +} + +static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, + const char *buf, const u32 *buf_int, + size_t count, bool hw_pattern) +{ + struct pattern_trig_data *data = led_cdev->trigger_data; + int err = 0; + + mutex_lock(&data->lock); + + del_timer_sync(&data->timer); + + if (data->is_hw_pattern) + led_cdev->pattern_clear(led_cdev); + + data->is_hw_pattern = hw_pattern; + data->npatterns = 0; + + if (buf) + err = pattern_trig_store_patterns_string(data, buf, count); + else + err = pattern_trig_store_patterns_int(data, buf_int, count); + if (err) + goto out; + err = pattern_trig_start_pattern(led_cdev); if (err) data->npatterns = 0; @@ -275,7 +303,7 @@ static ssize_t pattern_store(struct device *dev, struct device_attribute *attr, { struct led_classdev *led_cdev = dev_get_drvdata(dev); - return pattern_trig_store_patterns(led_cdev, buf, count, false); + return pattern_trig_store_patterns(led_cdev, buf, NULL, count, false); } static DEVICE_ATTR_RW(pattern); @@ -295,7 +323,7 @@ static ssize_t hw_pattern_store(struct device *dev, { struct led_classdev *led_cdev = dev_get_drvdata(dev); - return pattern_trig_store_patterns(led_cdev, buf, count, true); + return pattern_trig_store_patterns(led_cdev, buf, NULL, count, true); } static DEVICE_ATTR_RW(hw_pattern); @@ -331,6 +359,30 @@ static const struct attribute_group *pattern_trig_groups[] = { NULL, }; +static void pattern_init(struct led_classdev *led_cdev) +{ + unsigned int size = 0; + u32 *pattern; + int err; + + pattern = led_get_default_pattern(led_cdev, &size); + if (!pattern) + return; + + if (size % 2) { + dev_warn(led_cdev->dev, "Expected pattern of tuples\n"); + goto out; + } + + err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, false); + if (err < 0) + dev_warn(led_cdev->dev, + "Pattern initialization failed with error %d\n", err); + +out: + kfree(pattern); +} + static int pattern_trig_activate(struct led_classdev *led_cdev) { struct pattern_trig_data *data; @@ -354,6 +406,15 @@ static int pattern_trig_activate(struct led_classdev *led_cdev) timer_setup(&data->timer, pattern_trig_timer_function, 0); led_cdev->activated = true; + if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { + pattern_init(led_cdev); + /* + * Mark as initialized even on pattern_init() error because + * any consecutive call to it would produce the same error. + */ + led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; + } + return 0; } -- cgit v1.2.3 From 9c9ab51e86bf1f3a24eb3477cbe5d4fb09d386a5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 9 Jan 2019 15:44:48 +0100 Subject: leds: trigger: oneshot: Add initialization from Device Tree Allow initialization of delays used in oneshot trigger from Device Tree property. This is especially useful for embedded systems where the trigger might be used early, before bringing up user-space. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jacek Anaszewski --- drivers/leds/trigger/ledtrig-oneshot.c | 38 ++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/trigger/ledtrig-oneshot.c b/drivers/leds/trigger/ledtrig-oneshot.c index 95c9be4b6e7e..8808f0ad7339 100644 --- a/drivers/leds/trigger/ledtrig-oneshot.c +++ b/drivers/leds/trigger/ledtrig-oneshot.c @@ -130,6 +130,34 @@ static struct attribute *oneshot_trig_attrs[] = { }; ATTRIBUTE_GROUPS(oneshot_trig); +static void pattern_init(struct led_classdev *led_cdev) +{ + u32 *pattern; + unsigned int size = 0; + + pattern = led_get_default_pattern(led_cdev, &size); + if (!pattern) + goto out_default; + + if (size != 2) { + dev_warn(led_cdev->dev, + "Expected 2 but got %u values for delays pattern\n", + size); + goto out_default; + } + + led_cdev->blink_delay_on = pattern[0]; + led_cdev->blink_delay_off = pattern[1]; + kfree(pattern); + + return; + +out_default: + kfree(pattern); + led_cdev->blink_delay_on = DEFAULT_DELAY; + led_cdev->blink_delay_off = DEFAULT_DELAY; +} + static int oneshot_trig_activate(struct led_classdev *led_cdev) { struct oneshot_trig_data *oneshot_data; @@ -140,8 +168,14 @@ static int oneshot_trig_activate(struct led_classdev *led_cdev) led_set_trigger_data(led_cdev, oneshot_data); - led_cdev->blink_delay_on = DEFAULT_DELAY; - led_cdev->blink_delay_off = DEFAULT_DELAY; + if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { + pattern_init(led_cdev); + /* + * Mark as initialized even on pattern_init() error because + * any consecutive call to it would produce the same error. + */ + led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; + } return 0; } -- cgit v1.2.3 From 0f85e8498a482cbfdab91fb2d1b81c6c8c1cfd15 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 9 Jan 2019 15:44:49 +0100 Subject: leds: trigger: timer: Add initialization from Device Tree Allow initialization of delays used in timer trigger from Device Tree property. This is especially useful for embedded systems where the trigger might be used early, before bringing up user-space. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jacek Anaszewski --- drivers/leds/trigger/ledtrig-timer.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers') diff --git a/drivers/leds/trigger/ledtrig-timer.c b/drivers/leds/trigger/ledtrig-timer.c index 7c14983781ee..ca898c1383be 100644 --- a/drivers/leds/trigger/ledtrig-timer.c +++ b/drivers/leds/trigger/ledtrig-timer.c @@ -15,6 +15,7 @@ #include #include #include +#include #include static ssize_t led_delay_on_show(struct device *dev, @@ -77,8 +78,41 @@ static struct attribute *timer_trig_attrs[] = { }; ATTRIBUTE_GROUPS(timer_trig); +static void pattern_init(struct led_classdev *led_cdev) +{ + u32 *pattern; + unsigned int size = 0; + + pattern = led_get_default_pattern(led_cdev, &size); + if (!pattern) + return; + + if (size != 2) { + dev_warn(led_cdev->dev, + "Expected 2 but got %u values for delays pattern\n", + size); + goto out; + } + + led_cdev->blink_delay_on = pattern[0]; + led_cdev->blink_delay_off = pattern[1]; + /* led_blink_set() called by caller */ + +out: + kfree(pattern); +} + static int timer_trig_activate(struct led_classdev *led_cdev) { + if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { + pattern_init(led_cdev); + /* + * Mark as initialized even on pattern_init() error because + * any consecutive call to it would produce the same error. + */ + led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; + } + led_blink_set(led_cdev, &led_cdev->blink_delay_on, &led_cdev->blink_delay_off); -- cgit v1.2.3 From 9fb0969f75823e59f1af14d587aec279c66bf4a7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 14 Jan 2019 15:15:16 +0000 Subject: bnx2x: fix various indentation issues There are lines that have indentation issues, fix these. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h | 2 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 176 +++++++++++------------ drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 12 +- 4 files changed, 94 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h index 46ee2c01f4c5..066765fbef06 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h @@ -449,7 +449,7 @@ static inline void bnx2x_init_fw_wrr(const struct cmng_init_input *input_data, ccd[cos] = (u32)input_data->cos_min_rate[cos] * 100 * (T_FAIR_COEF / (8 * 100 * cosWeightSum)); - if (ccd[cos] < pdata->fair_vars.fair_threshold + if (ccd[cos] < pdata->fair_vars.fair_threshold + MIN_ABOVE_THRESH) { ccd[cos] = pdata->fair_vars.fair_threshold + diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 98d4c5a3ff21..29738dfa878c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -837,49 +837,45 @@ static int bnx2x_ets_e3b0_set_cos_bw(struct bnx2x *bp, switch (cos_entry) { case 0: - nig_reg_adress_crd_weight = - (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 : - NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0; - pbf_reg_adress_crd_weight = (port) ? - PBF_REG_COS0_WEIGHT_P1 : PBF_REG_COS0_WEIGHT_P0; - break; + nig_reg_adress_crd_weight = + (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0; + pbf_reg_adress_crd_weight = (port) ? + PBF_REG_COS0_WEIGHT_P1 : PBF_REG_COS0_WEIGHT_P0; + break; case 1: - nig_reg_adress_crd_weight = (port) ? - NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 : - NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1; - pbf_reg_adress_crd_weight = (port) ? - PBF_REG_COS1_WEIGHT_P1 : PBF_REG_COS1_WEIGHT_P0; - break; + nig_reg_adress_crd_weight = (port) ? + NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1; + pbf_reg_adress_crd_weight = (port) ? + PBF_REG_COS1_WEIGHT_P1 : PBF_REG_COS1_WEIGHT_P0; + break; case 2: - nig_reg_adress_crd_weight = (port) ? - NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 : - NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2; + nig_reg_adress_crd_weight = (port) ? + NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2; - pbf_reg_adress_crd_weight = (port) ? - PBF_REG_COS2_WEIGHT_P1 : PBF_REG_COS2_WEIGHT_P0; - break; + pbf_reg_adress_crd_weight = (port) ? + PBF_REG_COS2_WEIGHT_P1 : PBF_REG_COS2_WEIGHT_P0; + break; case 3: - if (port) + if (port) return -EINVAL; - nig_reg_adress_crd_weight = - NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3; - pbf_reg_adress_crd_weight = - PBF_REG_COS3_WEIGHT_P0; - break; + nig_reg_adress_crd_weight = NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3; + pbf_reg_adress_crd_weight = PBF_REG_COS3_WEIGHT_P0; + break; case 4: - if (port) - return -EINVAL; - nig_reg_adress_crd_weight = - NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4; - pbf_reg_adress_crd_weight = PBF_REG_COS4_WEIGHT_P0; - break; + if (port) + return -EINVAL; + nig_reg_adress_crd_weight = NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4; + pbf_reg_adress_crd_weight = PBF_REG_COS4_WEIGHT_P0; + break; case 5: - if (port) - return -EINVAL; - nig_reg_adress_crd_weight = - NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5; - pbf_reg_adress_crd_weight = PBF_REG_COS5_WEIGHT_P0; - break; + if (port) + return -EINVAL; + nig_reg_adress_crd_weight = NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5; + pbf_reg_adress_crd_weight = PBF_REG_COS5_WEIGHT_P0; + break; } REG_WR(bp, nig_reg_adress_crd_weight, cos_bw_nig); @@ -966,7 +962,7 @@ static int bnx2x_ets_e3b0_sp_pri_to_cos_set(const struct link_params *params, if (pri >= max_num_of_cos) { DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid " "parameter Illegal strict priority\n"); - return -EINVAL; + return -EINVAL; } if (sp_pri_to_cos[pri] != DCBX_INVALID_COS) { @@ -1845,28 +1841,28 @@ static int bnx2x_emac_enable(struct link_params *params, bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, EMAC_TX_MODE_RESET); - /* pause enable/disable */ - bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, - EMAC_RX_MODE_FLOW_EN); + /* pause enable/disable */ + bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); - bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, - (EMAC_TX_MODE_EXT_PAUSE_EN | - EMAC_TX_MODE_FLOW_EN)); - if (!(params->feature_config_flags & - FEATURE_CONFIG_PFC_ENABLED)) { - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) - bnx2x_bits_en(bp, emac_base + - EMAC_REG_EMAC_RX_MODE, - EMAC_RX_MODE_FLOW_EN); - - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) - bnx2x_bits_en(bp, emac_base + - EMAC_REG_EMAC_TX_MODE, - (EMAC_TX_MODE_EXT_PAUSE_EN | - EMAC_TX_MODE_FLOW_EN)); - } else - bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, - EMAC_TX_MODE_FLOW_EN); + bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + (EMAC_TX_MODE_EXT_PAUSE_EN | + EMAC_TX_MODE_FLOW_EN)); + if (!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED)) { + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) + bnx2x_bits_en(bp, emac_base + + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); + + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) + bnx2x_bits_en(bp, emac_base + + EMAC_REG_EMAC_TX_MODE, + (EMAC_TX_MODE_EXT_PAUSE_EN | + EMAC_TX_MODE_FLOW_EN)); + } else + bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + EMAC_TX_MODE_FLOW_EN); /* KEEP_VLAN_TAG, promiscuous */ val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE); @@ -6478,9 +6474,9 @@ int bnx2x_test_link(struct link_params *params, struct link_vars *vars, MDIO_REG_BANK_GP_STATUS, MDIO_GP_STATUS_TOP_AN_STATUS1, &gp_status); - /* Link is up only if both local phy and external phy are up */ - if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)) - return -ESRCH; + /* Link is up only if both local phy and external phy are up */ + if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)) + return -ESRCH; } /* In XGXS loopback mode, do not check external PHY */ if (params->loopback_mode == LOOPBACK_XGXS) @@ -7293,8 +7289,8 @@ static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy) DP(NETIF_MSG_LINK, "XAUI workaround has completed\n"); return 0; - } - usleep_range(3000, 6000); + } + usleep_range(3000, 6000); } break; } @@ -12675,39 +12671,39 @@ static void bnx2x_init_bmac_loopback(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; - vars->link_up = 1; - vars->line_speed = SPEED_10000; - vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; - vars->mac_type = MAC_TYPE_BMAC; + vars->link_up = 1; + vars->line_speed = SPEED_10000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_BMAC; - vars->phy_flags = PHY_XGXS_FLAG; + vars->phy_flags = PHY_XGXS_FLAG; - bnx2x_xgxs_deassert(params); + bnx2x_xgxs_deassert(params); - /* Set bmac loopback */ - bnx2x_bmac_enable(params, vars, 1, 1); + /* Set bmac loopback */ + bnx2x_bmac_enable(params, vars, 1, 1); - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port * 4, 0); } static void bnx2x_init_emac_loopback(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; - vars->link_up = 1; - vars->line_speed = SPEED_1000; - vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; - vars->mac_type = MAC_TYPE_EMAC; + vars->link_up = 1; + vars->line_speed = SPEED_1000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_EMAC; - vars->phy_flags = PHY_XGXS_FLAG; + vars->phy_flags = PHY_XGXS_FLAG; - bnx2x_xgxs_deassert(params); - /* Set bmac loopback */ - bnx2x_emac_enable(params, vars, 1); - bnx2x_emac_program(params, vars); - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + bnx2x_xgxs_deassert(params); + /* Set bmac loopback */ + bnx2x_emac_enable(params, vars, 1); + bnx2x_emac_program(params, vars); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port * 4, 0); } static void bnx2x_init_xmac_loopback(struct link_params *params, @@ -13073,12 +13069,12 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0); } - if (!CHIP_IS_E3(bp)) { - bnx2x_set_bmac_rx(bp, params->chip_id, port, 0); - } else { - bnx2x_set_xmac_rxtx(params, 0); - bnx2x_set_umac_rxtx(params, 0); - } + if (!CHIP_IS_E3(bp)) { + bnx2x_set_bmac_rx(bp, params->chip_id, port, 0); + } else { + bnx2x_set_xmac_rxtx(params, 0); + bnx2x_set_umac_rxtx(params, 0); + } /* Disable emac */ if (!CHIP_IS_E3(bp)) REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 3b5b47e98c73..0cec82450e19 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -11298,7 +11298,7 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg) dev_info.port_hw_config[port].external_phy_config), SHMEM_RD(bp, dev_info.port_hw_config[port].external_phy_config2)); - return; + return; } if (CHIP_IS_E3(bp)) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index a9eaaf3e73a4..7b22a6d8514c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -2977,8 +2977,8 @@ static inline void bnx2x_mcast_hdl_pending_del_e2(struct bnx2x *bp, cmd_pos->data.macs_num--; - DP(BNX2X_MSG_SP, "Deleting MAC. %d left,cnt is %d\n", - cmd_pos->data.macs_num, cnt); + DP(BNX2X_MSG_SP, "Deleting MAC. %d left,cnt is %d\n", + cmd_pos->data.macs_num, cnt); /* Break if we reached the maximum * number of rules. @@ -3597,8 +3597,8 @@ static int bnx2x_mcast_validate_e1(struct bnx2x *bp, /* RESTORE command will restore the entire multicast configuration */ case BNX2X_MCAST_CMD_RESTORE: p->mcast_list_len = reg_sz; - DP(BNX2X_MSG_SP, "Command %d, p->mcast_list_len=%d\n", - cmd, p->mcast_list_len); + DP(BNX2X_MSG_SP, "Command %d, p->mcast_list_len=%d\n", + cmd, p->mcast_list_len); break; case BNX2X_MCAST_CMD_ADD: @@ -3735,8 +3735,8 @@ static inline int bnx2x_mcast_handle_restore_cmd_e1( i++; - DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n", - cfg_data.mac); + DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n", + cfg_data.mac); } *rdata_idx = i; -- cgit v1.2.3 From eedfb2234bf77f2c17b68e702ce5c51ed4c72fbd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 14 Jan 2019 15:37:01 +0000 Subject: drivers: net: atp: fix various indentation issues There are various lines that have indentation issues, fix these. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/atp.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/realtek/atp.c b/drivers/net/ethernet/realtek/atp.c index 7e011c1c1e6e..cfb67b746595 100644 --- a/drivers/net/ethernet/realtek/atp.c +++ b/drivers/net/ethernet/realtek/atp.c @@ -454,14 +454,14 @@ static void hardware_init(struct net_device *dev) { struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; - int i; + int i; /* Turn off the printer multiplexer on the 8012. */ for (i = 0; i < 8; i++) outb(mux_8012[i], ioaddr + PAR_DATA); write_reg_high(ioaddr, CMR1, CMR1h_RESET); - for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); write_reg_high(ioaddr, CMR2, lp->addr_mode); @@ -471,15 +471,15 @@ static void hardware_init(struct net_device *dev) (read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f); } - write_reg(ioaddr, CMR2, CMR2_IRQOUT); - write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); + write_reg(ioaddr, CMR2, CMR2_IRQOUT); + write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); /* Enable the interrupt line from the serial port. */ outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); /* Unmask the interesting interrupts. */ - write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); - write_reg_high(ioaddr, IMR, ISRh_RxErr); + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); lp->tx_unit_busy = 0; lp->pac_cnt_in_tx_buf = 0; @@ -610,10 +610,12 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) write_reg(ioaddr, CMR2, CMR2_NULL); write_reg(ioaddr, IMR, 0); - if (net_debug > 5) printk(KERN_DEBUG "%s: In interrupt ", dev->name); - while (--boguscount > 0) { + if (net_debug > 5) + printk(KERN_DEBUG "%s: In interrupt ", dev->name); + while (--boguscount > 0) { int status = read_nibble(ioaddr, ISR); - if (net_debug > 5) printk("loop status %02x..", status); + if (net_debug > 5) + printk("loop status %02x..", status); if (status & (ISR_RxOK<<3)) { handled = 1; @@ -640,7 +642,8 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) } while (--boguscount > 0); } else if (status & ((ISR_TxErr + ISR_TxOK)<<3)) { handled = 1; - if (net_debug > 6) printk("handling Tx done.."); + if (net_debug > 6) + printk("handling Tx done.."); /* Clear the Tx interrupt. We should check for too many failures and reinitialize the adapter. */ write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK); @@ -680,7 +683,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) break; } else break; - } + } /* This following code fixes a rare (and very difficult to track down) problem where the adapter forgets its ethernet address. */ @@ -694,7 +697,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) } /* Tell the adapter that it can go back to using the output line as IRQ. */ - write_reg(ioaddr, CMR2, CMR2_IRQOUT); + write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Enable the physical interrupt line, which is sure to be low until.. */ outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); /* .. we enable the interrupt sources. */ -- cgit v1.2.3 From bdbe8cc1a30c7280bc5e6119fb5d37bfdd723c47 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 14 Jan 2019 15:41:25 +0000 Subject: net: sungem: fix indentation, remove a tab The declaration of variable 'found' is one level too deep, fix this by removing a tab. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/sungem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index b9221fc1674d..3e7631160384 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -2760,7 +2760,7 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) void __iomem *p = pci_map_rom(pdev, &size); if (p) { - int found; + int found; found = readb(p) == 0x55 && readb(p + 1) == 0xaa && -- cgit v1.2.3 From b26bf6ab716f27955e2a503ffca1691582127cbb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 4 Jan 2019 12:30:47 +0100 Subject: cpuidle: New timer events oriented governor for tickless systems The venerable menu governor does some things that are quite questionable in my view. First, it includes timer wakeups in the pattern detection data and mixes them up with wakeups from other sources which in some cases causes it to expect what essentially would be a timer wakeup in a time frame in which no timer wakeups are possible (because it knows the time until the next timer event and that is later than the expected wakeup time). Second, it uses the extra exit latency limit based on the predicted idle duration and depending on the number of tasks waiting on I/O, even though those tasks may run on a different CPU when they are woken up. Moreover, the time ranges used by it for the sleep length correction factors depend on whether or not there are tasks waiting on I/O, which again doesn't imply anything in particular, and they are not correlated to the list of available idle states in any way whatever. Also, the pattern detection code in menu may end up considering values that are too large to matter at all, in which cases running it is a waste of time. A major rework of the menu governor would be required to address these issues and the performance of at least some workloads (tuned specifically to the current behavior of the menu governor) is likely to suffer from that. It is thus better to introduce an entirely new governor without them and let everybody use the governor that works better with their actual workloads. The new governor introduced here, the timer events oriented (TEO) governor, uses the same basic strategy as menu: it always tries to find the deepest idle state that can be used in the given conditions. However, it applies a different approach to that problem. First, it doesn't use "correction factors" for the time till the closest timer, but instead it tries to correlate the measured idle duration values with the available idle states and use that information to pick up the idle state that is most likely to "match" the upcoming CPU idle interval. Second, it doesn't take the number of "I/O waiters" into account at all and the pattern detection code in it avoids taking timer wakeups into account. It also only uses idle duration values less than the current time till the closest timer (with the tick excluded) for that purpose. Signed-off-by: Rafael J. Wysocki Acked-by: Daniel Lezcano --- drivers/cpuidle/Kconfig | 11 +- drivers/cpuidle/governors/Makefile | 1 + drivers/cpuidle/governors/teo.c | 444 +++++++++++++++++++++++++++++++++++++ 3 files changed, 455 insertions(+), 1 deletion(-) create mode 100644 drivers/cpuidle/governors/teo.c (limited to 'drivers') diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 7e48eb5bf0a7..8caccbbd7353 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -4,7 +4,7 @@ config CPU_IDLE bool "CPU idle PM support" default y if ACPI || PPC_PSERIES select CPU_IDLE_GOV_LADDER if (!NO_HZ && !NO_HZ_IDLE) - select CPU_IDLE_GOV_MENU if (NO_HZ || NO_HZ_IDLE) + select CPU_IDLE_GOV_MENU if (NO_HZ || NO_HZ_IDLE) && !CPU_IDLE_GOV_TEO help CPU idle is a generic framework for supporting software-controlled idle processor power management. It includes modular cross-platform @@ -23,6 +23,15 @@ config CPU_IDLE_GOV_LADDER config CPU_IDLE_GOV_MENU bool "Menu governor (for tickless system)" +config CPU_IDLE_GOV_TEO + bool "Timer events oriented (TEO) governor (for tickless systems)" + help + This governor implements a simplified idle state selection method + focused on timer events and does not do any interactivity boosting. + + Some workloads benefit from using it and it generally should be safe + to use. Say Y here if you are not happy with the alternatives. + config DT_IDLE_STATES bool diff --git a/drivers/cpuidle/governors/Makefile b/drivers/cpuidle/governors/Makefile index 1b512722689f..4d8aff5248a8 100644 --- a/drivers/cpuidle/governors/Makefile +++ b/drivers/cpuidle/governors/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_CPU_IDLE_GOV_LADDER) += ladder.o obj-$(CONFIG_CPU_IDLE_GOV_MENU) += menu.o +obj-$(CONFIG_CPU_IDLE_GOV_TEO) += teo.o diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c new file mode 100644 index 000000000000..7d05efdbd3c6 --- /dev/null +++ b/drivers/cpuidle/governors/teo.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Timer events oriented CPU idle governor + * + * Copyright (C) 2018 Intel Corporation + * Author: Rafael J. Wysocki + * + * The idea of this governor is based on the observation that on many systems + * timer events are two or more orders of magnitude more frequent than any + * other interrupts, so they are likely to be the most significant source of CPU + * wakeups from idle states. Moreover, information about what happened in the + * (relatively recent) past can be used to estimate whether or not the deepest + * idle state with target residency within the time to the closest timer is + * likely to be suitable for the upcoming idle time of the CPU and, if not, then + * which of the shallower idle states to choose. + * + * Of course, non-timer wakeup sources are more important in some use cases and + * they can be covered by taking a few most recent idle time intervals of the + * CPU into account. However, even in that case it is not necessary to consider + * idle duration values greater than the time till the closest timer, as the + * patterns that they may belong to produce average values close enough to + * the time till the closest timer (sleep length) anyway. + * + * Thus this governor estimates whether or not the upcoming idle time of the CPU + * is likely to be significantly shorter than the sleep length and selects an + * idle state for it in accordance with that, as follows: + * + * - Find an idle state on the basis of the sleep length and state statistics + * collected over time: + * + * o Find the deepest idle state whose target residency is less than or equal + * to the sleep length. + * + * o Select it if it matched both the sleep length and the observed idle + * duration in the past more often than it matched the sleep length alone + * (i.e. the observed idle duration was significantly shorter than the sleep + * length matched by it). + * + * o Otherwise, select the shallower state with the greatest matched "early" + * wakeups metric. + * + * - If the majority of the most recent idle duration values are below the + * target residency of the idle state selected so far, use those values to + * compute the new expected idle duration and find an idle state matching it + * (which has to be shallower than the one selected so far). + */ + +#include +#include +#include +#include +#include + +/* + * The PULSE value is added to metrics when they grow and the DECAY_SHIFT value + * is used for decreasing metrics on a regular basis. + */ +#define PULSE 1024 +#define DECAY_SHIFT 3 + +/* + * Number of the most recent idle duration values to take into consideration for + * the detection of wakeup patterns. + */ +#define INTERVALS 8 + +/** + * struct teo_idle_state - Idle state data used by the TEO cpuidle governor. + * @early_hits: "Early" CPU wakeups "matching" this state. + * @hits: "On time" CPU wakeups "matching" this state. + * @misses: CPU wakeups "missing" this state. + * + * A CPU wakeup is "matched" by a given idle state if the idle duration measured + * after the wakeup is between the target residency of that state and the target + * residency of the next one (or if this is the deepest available idle state, it + * "matches" a CPU wakeup when the measured idle duration is at least equal to + * its target residency). + * + * Also, from the TEO governor perspective, a CPU wakeup from idle is "early" if + * it occurs significantly earlier than the closest expected timer event (that + * is, early enough to match an idle state shallower than the one matching the + * time till the closest timer event). Otherwise, the wakeup is "on time", or + * it is a "hit". + * + * A "miss" occurs when the given state doesn't match the wakeup, but it matches + * the time till the closest timer event used for idle state selection. + */ +struct teo_idle_state { + unsigned int early_hits; + unsigned int hits; + unsigned int misses; +}; + +/** + * struct teo_cpu - CPU data used by the TEO cpuidle governor. + * @time_span_ns: Time between idle state selection and post-wakeup update. + * @sleep_length_ns: Time till the closest timer event (at the selection time). + * @states: Idle states data corresponding to this CPU. + * @last_state: Idle state entered by the CPU last time. + * @interval_idx: Index of the most recent saved idle interval. + * @intervals: Saved idle duration values. + */ +struct teo_cpu { + u64 time_span_ns; + u64 sleep_length_ns; + struct teo_idle_state states[CPUIDLE_STATE_MAX]; + int last_state; + int interval_idx; + unsigned int intervals[INTERVALS]; +}; + +static DEFINE_PER_CPU(struct teo_cpu, teo_cpus); + +/** + * teo_update - Update CPU data after wakeup. + * @drv: cpuidle driver containing state data. + * @dev: Target CPU. + */ +static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) +{ + struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); + unsigned int sleep_length_us = ktime_to_us(cpu_data->sleep_length_ns); + int i, idx_hit = -1, idx_timer = -1; + unsigned int measured_us; + + if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) { + /* + * One of the safety nets has triggered or this was a timer + * wakeup (or equivalent). + */ + measured_us = sleep_length_us; + } else { + unsigned int lat = drv->states[cpu_data->last_state].exit_latency; + + measured_us = ktime_to_us(cpu_data->time_span_ns); + /* + * The delay between the wakeup and the first instruction + * executed by the CPU is not likely to be worst-case every + * time, so take 1/2 of the exit latency as a very rough + * approximation of the average of it. + */ + if (measured_us >= lat) + measured_us -= lat / 2; + else + measured_us /= 2; + } + + /* + * Decay the "early hits" metric for all of the states and find the + * states matching the sleep length and the measured idle duration. + */ + for (i = 0; i < drv->state_count; i++) { + unsigned int early_hits = cpu_data->states[i].early_hits; + + cpu_data->states[i].early_hits -= early_hits >> DECAY_SHIFT; + + if (drv->states[i].target_residency <= sleep_length_us) { + idx_timer = i; + if (drv->states[i].target_residency <= measured_us) + idx_hit = i; + } + } + + /* + * Update the "hits" and "misses" data for the state matching the sleep + * length. If it matches the measured idle duration too, this is a hit, + * so increase the "hits" metric for it then. Otherwise, this is a + * miss, so increase the "misses" metric for it. In the latter case + * also increase the "early hits" metric for the state that actually + * matches the measured idle duration. + */ + if (idx_timer >= 0) { + unsigned int hits = cpu_data->states[idx_timer].hits; + unsigned int misses = cpu_data->states[idx_timer].misses; + + hits -= hits >> DECAY_SHIFT; + misses -= misses >> DECAY_SHIFT; + + if (idx_timer > idx_hit) { + misses += PULSE; + if (idx_hit >= 0) + cpu_data->states[idx_hit].early_hits += PULSE; + } else { + hits += PULSE; + } + + cpu_data->states[idx_timer].misses = misses; + cpu_data->states[idx_timer].hits = hits; + } + + /* + * If the total time span between idle state selection and the "reflect" + * callback is greater than or equal to the sleep length determined at + * the idle state selection time, the wakeup is likely to be due to a + * timer event. + */ + if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) + measured_us = UINT_MAX; + + /* + * Save idle duration values corresponding to non-timer wakeups for + * pattern detection. + */ + cpu_data->intervals[cpu_data->interval_idx++] = measured_us; + if (cpu_data->interval_idx > INTERVALS) + cpu_data->interval_idx = 0; +} + +/** + * teo_find_shallower_state - Find shallower idle state matching given duration. + * @drv: cpuidle driver containing state data. + * @dev: Target CPU. + * @state_idx: Index of the capping idle state. + * @duration_us: Idle duration value to match. + */ +static int teo_find_shallower_state(struct cpuidle_driver *drv, + struct cpuidle_device *dev, int state_idx, + unsigned int duration_us) +{ + int i; + + for (i = state_idx - 1; i >= 0; i--) { + if (drv->states[i].disabled || dev->states_usage[i].disable) + continue; + + state_idx = i; + if (drv->states[i].target_residency <= duration_us) + break; + } + return state_idx; +} + +/** + * teo_select - Selects the next idle state to enter. + * @drv: cpuidle driver containing state data. + * @dev: Target CPU. + * @stop_tick: Indication on whether or not to stop the scheduler tick. + */ +static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + bool *stop_tick) +{ + struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); + int latency_req = cpuidle_governor_latency_req(dev->cpu); + unsigned int duration_us, count; + int max_early_idx, idx, i; + ktime_t delta_tick; + + if (cpu_data->last_state >= 0) { + teo_update(drv, dev); + cpu_data->last_state = -1; + } + + cpu_data->time_span_ns = local_clock(); + + cpu_data->sleep_length_ns = tick_nohz_get_sleep_length(&delta_tick); + duration_us = ktime_to_us(cpu_data->sleep_length_ns); + + count = 0; + max_early_idx = -1; + idx = -1; + + for (i = 0; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; + struct cpuidle_state_usage *su = &dev->states_usage[i]; + + if (s->disabled || su->disable) { + /* + * If the "early hits" metric of a disabled state is + * greater than the current maximum, it should be taken + * into account, because it would be a mistake to select + * a deeper state with lower "early hits" metric. The + * index cannot be changed to point to it, however, so + * just increase the max count alone and let the index + * still point to a shallower idle state. + */ + if (max_early_idx >= 0 && + count < cpu_data->states[i].early_hits) + count = cpu_data->states[i].early_hits; + + continue; + } + + if (idx < 0) + idx = i; /* first enabled state */ + + if (s->target_residency > duration_us) + break; + + if (s->exit_latency > latency_req) { + /* + * If we break out of the loop for latency reasons, use + * the target residency of the selected state as the + * expected idle duration to avoid stopping the tick + * as long as that target residency is low enough. + */ + duration_us = drv->states[idx].target_residency; + goto refine; + } + + idx = i; + + if (count < cpu_data->states[i].early_hits && + !(tick_nohz_tick_stopped() && + drv->states[i].target_residency < TICK_USEC)) { + count = cpu_data->states[i].early_hits; + max_early_idx = i; + } + } + + /* + * If the "hits" metric of the idle state matching the sleep length is + * greater than its "misses" metric, that is the one to use. Otherwise, + * it is more likely that one of the shallower states will match the + * idle duration observed after wakeup, so take the one with the maximum + * "early hits" metric, but if that cannot be determined, just use the + * state selected so far. + */ + if (cpu_data->states[idx].hits <= cpu_data->states[idx].misses && + max_early_idx >= 0) { + idx = max_early_idx; + duration_us = drv->states[idx].target_residency; + } + +refine: + if (idx < 0) { + idx = 0; /* No states enabled. Must use 0. */ + } else if (idx > 0) { + u64 sum = 0; + + count = 0; + + /* + * Count and sum the most recent idle duration values less than + * the target residency of the state selected so far, find the + * max. + */ + for (i = 0; i < INTERVALS; i++) { + unsigned int val = cpu_data->intervals[i]; + + if (val >= drv->states[idx].target_residency) + continue; + + count++; + sum += val; + } + + /* + * Give up unless the majority of the most recent idle duration + * values are in the interesting range. + */ + if (count > INTERVALS / 2) { + unsigned int avg_us = div64_u64(sum, count); + + /* + * Avoid spending too much time in an idle state that + * would be too shallow. + */ + if (!(tick_nohz_tick_stopped() && avg_us < TICK_USEC)) { + idx = teo_find_shallower_state(drv, dev, idx, avg_us); + duration_us = avg_us; + } + } + } + + /* + * Don't stop the tick if the selected state is a polling one or if the + * expected idle duration is shorter than the tick period length. + */ + if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || + duration_us < TICK_USEC) && !tick_nohz_tick_stopped()) { + unsigned int delta_tick_us = ktime_to_us(delta_tick); + + *stop_tick = false; + + /* + * The tick is not going to be stopped, so if the target + * residency of the state to be returned is not within the time + * till the closest timer including the tick, try to correct + * that. + */ + if (idx > 0 && drv->states[idx].target_residency > delta_tick_us) + idx = teo_find_shallower_state(drv, dev, idx, delta_tick_us); + } + + return idx; +} + +/** + * teo_reflect - Note that governor data for the CPU need to be updated. + * @dev: Target CPU. + * @state: Entered state. + */ +static void teo_reflect(struct cpuidle_device *dev, int state) +{ + struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); + + cpu_data->last_state = state; + /* + * If the wakeup was not "natural", but triggered by one of the safety + * nets, assume that the CPU might have been idle for the entire sleep + * length time. + */ + if (dev->poll_time_limit || + (tick_nohz_idle_got_tick() && cpu_data->sleep_length_ns > TICK_NSEC)) { + dev->poll_time_limit = false; + cpu_data->time_span_ns = cpu_data->sleep_length_ns; + } else { + cpu_data->time_span_ns = local_clock() - cpu_data->time_span_ns; + } +} + +/** + * teo_enable_device - Initialize the governor's data for the target CPU. + * @drv: cpuidle driver (not used). + * @dev: Target CPU. + */ +static int teo_enable_device(struct cpuidle_driver *drv, + struct cpuidle_device *dev) +{ + struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); + int i; + + memset(cpu_data, 0, sizeof(*cpu_data)); + + for (i = 0; i < INTERVALS; i++) + cpu_data->intervals[i] = UINT_MAX; + + return 0; +} + +static struct cpuidle_governor teo_governor = { + .name = "teo", + .rating = 19, + .enable = teo_enable_device, + .select = teo_select, + .reflect = teo_reflect, +}; + +static int __init teo_governor_init(void) +{ + return cpuidle_register_governor(&teo_governor); +} + +postcore_initcall(teo_governor_init); -- cgit v1.2.3 From 96439889b40b83b487fa08637dcc74b1243362af Mon Sep 17 00:00:00 2001 From: Fred Lotter Date: Tue, 15 Jan 2019 19:06:51 -0800 Subject: nfp: flower: increase cmesg reply timeout QA tests report occasional timeouts on REIFY message replies. Profiling of the two cmesg reply types under burst conditions, with a 12-core host under heavy cpu and io load (stress --cpu 12 --io 12), show both PHY MTU change and REIFY replies can exceed the 10ms timeout. The maximum MTU reply wait under burst is 16ms, while the maximum REIFY wait under 40 VF burst is 12ms. Using a 4 VF REIFY burst results in an 8ms maximum wait. A larger VF burst does increase the delay, but not in a linear enough way to justify a scaled REIFY delay. The worse case values between MTU and REIFY appears close enough to justify a common timeout. Pick a conservative 40ms to make a safer future proof common reply timeout. The delay only effects the failure case. Change the REIFY timeout mechanism to use wait_event_timeout() instead of wait_event_interruptible_timeout(), to match the MTU code. In the current implementation, theoretically, a signal could interrupt the REIFY waiting period, with a return code of ERESTARTSYS. However, this is caught under the general timeout error code EIO. I cannot see the benefit of exposing the REIFY waiting period to signals with such a short delay (40ms), while the MTU mechnism does not use the same logic. In the absence of any reply (wakeup() call), both reply types will wake up the task after the timeout period. The REIFY timeout applies to the entire representor group being instantiated (e.g. VFs), while the MTU timeout apples to a single PHY MTU change. Signed-off-by: Fred Lotter Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 2 +- drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 3 +++ drivers/net/ethernet/netronome/nfp/flower/main.c | 18 +++++++----------- 3 files changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c index 4c5eaf36d5bb..56b22ea32474 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c @@ -203,7 +203,7 @@ nfp_flower_cmsg_portreify_rx(struct nfp_app *app, struct sk_buff *skb) } atomic_inc(&priv->reify_replies); - wake_up_interruptible(&priv->reify_wait_queue); + wake_up(&priv->reify_wait_queue); } static void diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index 15f41cfef9f1..4fcaf11ed56e 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -97,6 +97,9 @@ #define NFP_FLOWER_WORKQ_MAX_SKBS 30000 +/* Cmesg reply (empirical) timeout*/ +#define NFP_FL_REPLY_TIMEOUT msecs_to_jiffies(40) + #define nfp_flower_cmsg_warn(app, fmt, args...) \ do { \ if (net_ratelimit()) \ diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 5059110a1768..8ce20bd38965 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -107,16 +107,14 @@ static int nfp_flower_wait_repr_reify(struct nfp_app *app, atomic_t *replies, int tot_repl) { struct nfp_flower_priv *priv = app->priv; - int err; if (!tot_repl) return 0; lockdep_assert_held(&app->pf->lock); - err = wait_event_interruptible_timeout(priv->reify_wait_queue, - atomic_read(replies) >= tot_repl, - msecs_to_jiffies(10)); - if (err <= 0) { + if (!wait_event_timeout(priv->reify_wait_queue, + atomic_read(replies) >= tot_repl, + NFP_FL_REPLY_TIMEOUT)) { nfp_warn(app->cpp, "Not all reprs responded to reify\n"); return -EIO; } @@ -601,7 +599,7 @@ nfp_flower_repr_change_mtu(struct nfp_app *app, struct net_device *netdev, { struct nfp_flower_priv *app_priv = app->priv; struct nfp_repr *repr = netdev_priv(netdev); - int err, ack; + int err; /* Only need to config FW for physical port MTU change. */ if (repr->port->type != NFP_PORT_PHYS_PORT) @@ -628,11 +626,9 @@ nfp_flower_repr_change_mtu(struct nfp_app *app, struct net_device *netdev, } /* Wait for fw to ack the change. */ - ack = wait_event_timeout(app_priv->mtu_conf.wait_q, - nfp_flower_check_ack(app_priv), - msecs_to_jiffies(10)); - - if (!ack) { + if (!wait_event_timeout(app_priv->mtu_conf.wait_q, + nfp_flower_check_ack(app_priv), + NFP_FL_REPLY_TIMEOUT)) { spin_lock_bh(&app_priv->mtu_conf.lock); app_priv->mtu_conf.requested_val = 0; spin_unlock_bh(&app_priv->mtu_conf.lock); -- cgit v1.2.3 From 467322e2627f863c8b48b0229674d9a22027e559 Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Tue, 15 Jan 2019 19:06:52 -0800 Subject: nfp: flower: support multiple memory units for filter offloads Adds support for multiple memory units which are used for filter offloads. Each filter is assigned a stats id, the MSBs of the id are used to determine which memory unit the filter should be offloaded to. The number of available memory units that could be used for filter offload is obtained from HW. A simple round robin technique is used to allocate and distribute the ids across memory units. Signed-off-by: Pieter Jansen van Vuuren Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.c | 23 ++++++++++++++++-- drivers/net/ethernet/netronome/nfp/flower/main.h | 10 +++++++- .../net/ethernet/netronome/nfp/flower/metadata.c | 27 ++++++++++++++++------ 3 files changed, 50 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 8ce20bd38965..c370fbcbcc38 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -474,8 +474,8 @@ err_clear_nn: static int nfp_flower_init(struct nfp_app *app) { + u64 version, features, ctx_count, num_mems; const struct nfp_pf *pf = app->pf; - u64 version, features, ctx_count; struct nfp_flower_priv *app_priv; int err; @@ -500,6 +500,23 @@ static int nfp_flower_init(struct nfp_app *app) return err; } + num_mems = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_SPLIT", + &err); + if (err) { + nfp_warn(app->cpp, + "FlowerNIC: unsupported host context memory: %d\n", + err); + err = 0; + num_mems = 1; + } + + if (!FIELD_FIT(NFP_FL_STAT_ID_MU_NUM, num_mems) || !num_mems) { + nfp_warn(app->cpp, + "FlowerNIC: invalid host context memory: %llu\n", + num_mems); + return -EINVAL; + } + ctx_count = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_COUNT", &err); if (err) { @@ -520,6 +537,8 @@ static int nfp_flower_init(struct nfp_app *app) if (!app_priv) return -ENOMEM; + app_priv->total_mem_units = num_mems; + app_priv->active_mem_unit = 0; app_priv->stats_ring_size = roundup_pow_of_two(ctx_count); app->priv = app_priv; app_priv->app = app; @@ -531,7 +550,7 @@ static int nfp_flower_init(struct nfp_app *app) init_waitqueue_head(&app_priv->mtu_conf.wait_q); spin_lock_init(&app_priv->mtu_conf.lock); - err = nfp_flower_metadata_init(app, ctx_count); + err = nfp_flower_metadata_init(app, ctx_count, num_mems); if (err) goto err_free_app_priv; diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index b858bac47621..324b7fe3192f 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -20,6 +20,9 @@ struct nfp_fl_pre_lag; struct net_device; struct nfp_app; +#define NFP_FL_STAT_ID_MU_NUM GENMASK(31, 22) +#define NFP_FL_STAT_ID_STAT GENMASK(21, 0) + #define NFP_FL_STATS_ELEM_RS FIELD_SIZEOF(struct nfp_fl_stats_id, \ init_unalloc) #define NFP_FLOWER_MASK_ENTRY_RS 256 @@ -130,6 +133,8 @@ struct nfp_fl_lag { * @mtu_conf: Configuration of repr MTU value * @nfp_lag: Link aggregation data block * @indr_block_cb_priv: List of priv data passed to indirect block cbs + * @active_mem_unit: Current active memory unit for flower rules + * @total_mem_units: Total number of available memory units for flower rules */ struct nfp_flower_priv { struct nfp_app *app; @@ -163,6 +168,8 @@ struct nfp_flower_priv { struct nfp_mtu_conf mtu_conf; struct nfp_fl_lag nfp_lag; struct list_head indr_block_cb_priv; + unsigned int active_mem_unit; + unsigned int total_mem_units; }; /** @@ -217,7 +224,8 @@ struct nfp_fl_stats_frame { __be64 stats_cookie; }; -int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count); +int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count, + unsigned int host_ctx_split); void nfp_flower_metadata_cleanup(struct nfp_app *app); int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev, diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index 573a4400a26c..492837b852b6 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -52,8 +53,17 @@ static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id) freed_stats_id = priv->stats_ring_size; /* Check for unallocated entries first. */ if (priv->stats_ids.init_unalloc > 0) { - *stats_context_id = priv->stats_ids.init_unalloc - 1; - priv->stats_ids.init_unalloc--; + if (priv->active_mem_unit == priv->total_mem_units) { + priv->stats_ids.init_unalloc--; + priv->active_mem_unit = 0; + } + + *stats_context_id = + FIELD_PREP(NFP_FL_STAT_ID_STAT, + priv->stats_ids.init_unalloc - 1) | + FIELD_PREP(NFP_FL_STAT_ID_MU_NUM, + priv->active_mem_unit); + priv->active_mem_unit++; return 0; } @@ -381,10 +391,11 @@ const struct rhashtable_params nfp_flower_table_params = { .automatic_shrinking = true, }; -int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count) +int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count, + unsigned int host_num_mems) { struct nfp_flower_priv *priv = app->priv; - int err; + int err, stats_size; hash_init(priv->mask_table); @@ -417,10 +428,12 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count) if (!priv->stats_ids.free_list.buf) goto err_free_last_used; - priv->stats_ids.init_unalloc = host_ctx_count; + priv->stats_ids.init_unalloc = div_u64(host_ctx_count, host_num_mems); - priv->stats = kvmalloc_array(priv->stats_ring_size, - sizeof(struct nfp_fl_stats), GFP_KERNEL); + stats_size = FIELD_PREP(NFP_FL_STAT_ID_STAT, host_ctx_count) | + FIELD_PREP(NFP_FL_STAT_ID_MU_NUM, host_num_mems - 1); + priv->stats = kvmalloc_array(stats_size, sizeof(struct nfp_fl_stats), + GFP_KERNEL); if (!priv->stats) goto err_free_ring_buf; -- cgit v1.2.3 From f3b975778c176b01eba10f869a5a64c6b8550c23 Mon Sep 17 00:00:00 2001 From: John Hurley Date: Tue, 15 Jan 2019 19:06:53 -0800 Subject: nfp: flower: tidy tunnel related private data Recent additions to the flower app private data have grouped the variables of a given feature into a struct and added that struct to the main private data struct. In keeping with this, move all tunnel related private data to their own struct. This has no affect on functionality but improves readability and maintenance of the code. Signed-off-by: John Hurley Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.h | 52 ++++---- .../ethernet/netronome/nfp/flower/tunnel_conf.c | 144 ++++++++++----------- 2 files changed, 102 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 324b7fe3192f..977667ae0b5a 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -56,6 +56,34 @@ struct nfp_fl_stats_id { u8 repeated_em_count; }; +/** + * struct nfp_fl_tunnel_offloads - priv data for tunnel offloads + * @mac_off_list: List of MAC addresses to offload + * @mac_index_list: List of unique 8-bit indexes for non NFP netdevs + * @ipv4_off_list: List of IPv4 addresses to offload + * @neigh_off_list: List of neighbour offloads + * @mac_off_lock: Lock for the MAC address list + * @mac_index_lock: Lock for the MAC index list + * @ipv4_off_lock: Lock for the IPv4 address list + * @neigh_off_lock: Lock for the neighbour address list + * @mac_off_ids: IDA to manage id assignment for offloaded MACs + * @mac_off_count: Number of MACs in address list + * @neigh_nb: Notifier to monitor neighbour state + */ +struct nfp_fl_tunnel_offloads { + struct list_head mac_off_list; + struct list_head mac_index_list; + struct list_head ipv4_off_list; + struct list_head neigh_off_list; + struct mutex mac_off_lock; + struct mutex mac_index_lock; + struct mutex ipv4_off_lock; + spinlock_t neigh_off_lock; + struct ida mac_off_ids; + int mac_off_count; + struct notifier_block neigh_nb; +}; + /** * struct nfp_mtu_conf - manage MTU setting * @portnum: NFP port number of repr with requested MTU change @@ -116,17 +144,7 @@ struct nfp_fl_lag { * processing * @cmsg_skbs_low: List of lower priority skbs for control message * processing - * @nfp_mac_off_list: List of MAC addresses to offload - * @nfp_mac_index_list: List of unique 8-bit indexes for non NFP netdevs - * @nfp_ipv4_off_list: List of IPv4 addresses to offload - * @nfp_neigh_off_list: List of neighbour offloads - * @nfp_mac_off_lock: Lock for the MAC address list - * @nfp_mac_index_lock: Lock for the MAC index list - * @nfp_ipv4_off_lock: Lock for the IPv4 address list - * @nfp_neigh_off_lock: Lock for the neighbour address list - * @nfp_mac_off_ids: IDA to manage id assignment for offloaded macs - * @nfp_mac_off_count: Number of MACs in address list - * @nfp_tun_neigh_nb: Notifier to monitor neighbour state + * @tun: Tunnel offload data * @reify_replies: atomically stores the number of replies received * from firmware for repr reify * @reify_wait_queue: wait queue for repr reify response counting @@ -152,17 +170,7 @@ struct nfp_flower_priv { struct work_struct cmsg_work; struct sk_buff_head cmsg_skbs_high; struct sk_buff_head cmsg_skbs_low; - struct list_head nfp_mac_off_list; - struct list_head nfp_mac_index_list; - struct list_head nfp_ipv4_off_list; - struct list_head nfp_neigh_off_list; - struct mutex nfp_mac_off_lock; - struct mutex nfp_mac_index_lock; - struct mutex nfp_ipv4_off_lock; - spinlock_t nfp_neigh_off_lock; - struct ida nfp_mac_off_ids; - int nfp_mac_off_count; - struct notifier_block nfp_tun_neigh_nb; + struct nfp_fl_tunnel_offloads tun; atomic_t reify_replies; wait_queue_head_t reify_wait_queue; struct nfp_mtu_conf mtu_conf; diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 2d9f26a725c2..3026ab178fd2 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -205,15 +205,15 @@ static bool nfp_tun_has_route(struct nfp_app *app, __be32 ipv4_addr) struct nfp_ipv4_route_entry *entry; struct list_head *ptr, *storage; - spin_lock_bh(&priv->nfp_neigh_off_lock); - list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) { + spin_lock_bh(&priv->tun.neigh_off_lock); + list_for_each_safe(ptr, storage, &priv->tun.neigh_off_list) { entry = list_entry(ptr, struct nfp_ipv4_route_entry, list); if (entry->ipv4_addr == ipv4_addr) { - spin_unlock_bh(&priv->nfp_neigh_off_lock); + spin_unlock_bh(&priv->tun.neigh_off_lock); return true; } } - spin_unlock_bh(&priv->nfp_neigh_off_lock); + spin_unlock_bh(&priv->tun.neigh_off_lock); return false; } @@ -223,24 +223,24 @@ static void nfp_tun_add_route_to_cache(struct nfp_app *app, __be32 ipv4_addr) struct nfp_ipv4_route_entry *entry; struct list_head *ptr, *storage; - spin_lock_bh(&priv->nfp_neigh_off_lock); - list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) { + spin_lock_bh(&priv->tun.neigh_off_lock); + list_for_each_safe(ptr, storage, &priv->tun.neigh_off_list) { entry = list_entry(ptr, struct nfp_ipv4_route_entry, list); if (entry->ipv4_addr == ipv4_addr) { - spin_unlock_bh(&priv->nfp_neigh_off_lock); + spin_unlock_bh(&priv->tun.neigh_off_lock); return; } } entry = kmalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) { - spin_unlock_bh(&priv->nfp_neigh_off_lock); + spin_unlock_bh(&priv->tun.neigh_off_lock); nfp_flower_cmsg_warn(app, "Mem error when storing new route.\n"); return; } entry->ipv4_addr = ipv4_addr; - list_add_tail(&entry->list, &priv->nfp_neigh_off_list); - spin_unlock_bh(&priv->nfp_neigh_off_lock); + list_add_tail(&entry->list, &priv->tun.neigh_off_list); + spin_unlock_bh(&priv->tun.neigh_off_lock); } static void nfp_tun_del_route_from_cache(struct nfp_app *app, __be32 ipv4_addr) @@ -249,8 +249,8 @@ static void nfp_tun_del_route_from_cache(struct nfp_app *app, __be32 ipv4_addr) struct nfp_ipv4_route_entry *entry; struct list_head *ptr, *storage; - spin_lock_bh(&priv->nfp_neigh_off_lock); - list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) { + spin_lock_bh(&priv->tun.neigh_off_lock); + list_for_each_safe(ptr, storage, &priv->tun.neigh_off_list) { entry = list_entry(ptr, struct nfp_ipv4_route_entry, list); if (entry->ipv4_addr == ipv4_addr) { list_del(&entry->list); @@ -258,7 +258,7 @@ static void nfp_tun_del_route_from_cache(struct nfp_app *app, __be32 ipv4_addr) break; } } - spin_unlock_bh(&priv->nfp_neigh_off_lock); + spin_unlock_bh(&priv->tun.neigh_off_lock); } static void @@ -326,7 +326,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event, if (!nfp_netdev_is_nfp_repr(n->dev)) return NOTIFY_DONE; - app_priv = container_of(nb, struct nfp_flower_priv, nfp_tun_neigh_nb); + app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb); app = app_priv->app; /* Only concerned with changes to routes already added to NFP. */ @@ -401,11 +401,11 @@ static void nfp_tun_write_ipv4_list(struct nfp_app *app) int count; memset(&payload, 0, sizeof(struct nfp_tun_ipv4_addr)); - mutex_lock(&priv->nfp_ipv4_off_lock); + mutex_lock(&priv->tun.ipv4_off_lock); count = 0; - list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) { + list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) { if (count >= NFP_FL_IPV4_ADDRS_MAX) { - mutex_unlock(&priv->nfp_ipv4_off_lock); + mutex_unlock(&priv->tun.ipv4_off_lock); nfp_flower_cmsg_warn(app, "IPv4 offload exceeds limit.\n"); return; } @@ -413,7 +413,7 @@ static void nfp_tun_write_ipv4_list(struct nfp_app *app) payload.ipv4_addr[count++] = entry->ipv4_addr; } payload.count = cpu_to_be32(count); - mutex_unlock(&priv->nfp_ipv4_off_lock); + mutex_unlock(&priv->tun.ipv4_off_lock); nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_IPS, sizeof(struct nfp_tun_ipv4_addr), @@ -426,26 +426,26 @@ void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4) struct nfp_ipv4_addr_entry *entry; struct list_head *ptr, *storage; - mutex_lock(&priv->nfp_ipv4_off_lock); - list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) { + mutex_lock(&priv->tun.ipv4_off_lock); + list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) { entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list); if (entry->ipv4_addr == ipv4) { entry->ref_count++; - mutex_unlock(&priv->nfp_ipv4_off_lock); + mutex_unlock(&priv->tun.ipv4_off_lock); return; } } entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { - mutex_unlock(&priv->nfp_ipv4_off_lock); + mutex_unlock(&priv->tun.ipv4_off_lock); nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n"); return; } entry->ipv4_addr = ipv4; entry->ref_count = 1; - list_add_tail(&entry->list, &priv->nfp_ipv4_off_list); - mutex_unlock(&priv->nfp_ipv4_off_lock); + list_add_tail(&entry->list, &priv->tun.ipv4_off_list); + mutex_unlock(&priv->tun.ipv4_off_lock); nfp_tun_write_ipv4_list(app); } @@ -456,8 +456,8 @@ void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4) struct nfp_ipv4_addr_entry *entry; struct list_head *ptr, *storage; - mutex_lock(&priv->nfp_ipv4_off_lock); - list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) { + mutex_lock(&priv->tun.ipv4_off_lock); + list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) { entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list); if (entry->ipv4_addr == ipv4) { entry->ref_count--; @@ -468,7 +468,7 @@ void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4) break; } } - mutex_unlock(&priv->nfp_ipv4_off_lock); + mutex_unlock(&priv->tun.ipv4_off_lock); nfp_tun_write_ipv4_list(app); } @@ -481,25 +481,25 @@ void nfp_tunnel_write_macs(struct nfp_app *app) struct list_head *ptr, *storage; int mac_count, err, pay_size; - mutex_lock(&priv->nfp_mac_off_lock); - if (!priv->nfp_mac_off_count) { - mutex_unlock(&priv->nfp_mac_off_lock); + mutex_lock(&priv->tun.mac_off_lock); + if (!priv->tun.mac_off_count) { + mutex_unlock(&priv->tun.mac_off_lock); return; } pay_size = sizeof(struct nfp_tun_mac_addr) + - sizeof(struct index_mac_addr) * priv->nfp_mac_off_count; + sizeof(struct index_mac_addr) * priv->tun.mac_off_count; payload = kzalloc(pay_size, GFP_KERNEL); if (!payload) { - mutex_unlock(&priv->nfp_mac_off_lock); + mutex_unlock(&priv->tun.mac_off_lock); return; } - payload->count = cpu_to_be16(priv->nfp_mac_off_count); + payload->count = cpu_to_be16(priv->tun.mac_off_count); mac_count = 0; - list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) { + list_for_each_safe(ptr, storage, &priv->tun.mac_off_list) { entry = list_entry(ptr, struct nfp_tun_mac_offload_entry, list); payload->addresses[mac_count].index = entry->index; @@ -514,21 +514,21 @@ void nfp_tunnel_write_macs(struct nfp_app *app) kfree(payload); if (err) { - mutex_unlock(&priv->nfp_mac_off_lock); + mutex_unlock(&priv->tun.mac_off_lock); /* Write failed so retain list for future retry. */ return; } /* If list was successfully offloaded, flush it. */ - list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) { + list_for_each_safe(ptr, storage, &priv->tun.mac_off_list) { entry = list_entry(ptr, struct nfp_tun_mac_offload_entry, list); list_del(&entry->list); kfree(entry); } - priv->nfp_mac_off_count = 0; - mutex_unlock(&priv->nfp_mac_off_lock); + priv->tun.mac_off_count = 0; + mutex_unlock(&priv->tun.mac_off_lock); } static int nfp_tun_get_mac_idx(struct nfp_app *app, int ifindex) @@ -538,32 +538,32 @@ static int nfp_tun_get_mac_idx(struct nfp_app *app, int ifindex) struct list_head *ptr, *storage; int idx; - mutex_lock(&priv->nfp_mac_index_lock); - list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) { + mutex_lock(&priv->tun.mac_index_lock); + list_for_each_safe(ptr, storage, &priv->tun.mac_index_list) { entry = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list); if (entry->ifindex == ifindex) { idx = entry->index; - mutex_unlock(&priv->nfp_mac_index_lock); + mutex_unlock(&priv->tun.mac_index_lock); return idx; } } - idx = ida_simple_get(&priv->nfp_mac_off_ids, 0, + idx = ida_simple_get(&priv->tun.mac_off_ids, 0, NFP_MAX_MAC_INDEX, GFP_KERNEL); if (idx < 0) { - mutex_unlock(&priv->nfp_mac_index_lock); + mutex_unlock(&priv->tun.mac_index_lock); return idx; } entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { - mutex_unlock(&priv->nfp_mac_index_lock); + mutex_unlock(&priv->tun.mac_index_lock); return -ENOMEM; } entry->ifindex = ifindex; entry->index = idx; - list_add_tail(&entry->list, &priv->nfp_mac_index_list); - mutex_unlock(&priv->nfp_mac_index_lock); + list_add_tail(&entry->list, &priv->tun.mac_index_list); + mutex_unlock(&priv->tun.mac_index_lock); return idx; } @@ -574,18 +574,18 @@ static void nfp_tun_del_mac_idx(struct nfp_app *app, int ifindex) struct nfp_tun_mac_non_nfp_idx *entry; struct list_head *ptr, *storage; - mutex_lock(&priv->nfp_mac_index_lock); - list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) { + mutex_lock(&priv->tun.mac_index_lock); + list_for_each_safe(ptr, storage, &priv->tun.mac_index_list) { entry = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list); if (entry->ifindex == ifindex) { - ida_simple_remove(&priv->nfp_mac_off_ids, + ida_simple_remove(&priv->tun.mac_off_ids, entry->index); list_del(&entry->list); kfree(entry); break; } } - mutex_unlock(&priv->nfp_mac_index_lock); + mutex_unlock(&priv->tun.mac_index_lock); } static void nfp_tun_add_to_mac_offload_list(struct net_device *netdev, @@ -633,10 +633,10 @@ static void nfp_tun_add_to_mac_offload_list(struct net_device *netdev, entry->index = cpu_to_be16(nfp_mac_idx); ether_addr_copy(entry->addr, netdev->dev_addr); - mutex_lock(&priv->nfp_mac_off_lock); - priv->nfp_mac_off_count++; - list_add_tail(&entry->list, &priv->nfp_mac_off_list); - mutex_unlock(&priv->nfp_mac_off_lock); + mutex_lock(&priv->tun.mac_off_lock); + priv->tun.mac_off_count++; + list_add_tail(&entry->list, &priv->tun.mac_off_list); + mutex_unlock(&priv->tun.mac_off_lock); } int nfp_tunnel_mac_event_handler(struct nfp_app *app, @@ -662,23 +662,23 @@ int nfp_tunnel_config_start(struct nfp_app *app) struct nfp_flower_priv *priv = app->priv; /* Initialise priv data for MAC offloading. */ - priv->nfp_mac_off_count = 0; - mutex_init(&priv->nfp_mac_off_lock); - INIT_LIST_HEAD(&priv->nfp_mac_off_list); - mutex_init(&priv->nfp_mac_index_lock); - INIT_LIST_HEAD(&priv->nfp_mac_index_list); - ida_init(&priv->nfp_mac_off_ids); + priv->tun.mac_off_count = 0; + mutex_init(&priv->tun.mac_off_lock); + INIT_LIST_HEAD(&priv->tun.mac_off_list); + mutex_init(&priv->tun.mac_index_lock); + INIT_LIST_HEAD(&priv->tun.mac_index_list); + ida_init(&priv->tun.mac_off_ids); /* Initialise priv data for IPv4 offloading. */ - mutex_init(&priv->nfp_ipv4_off_lock); - INIT_LIST_HEAD(&priv->nfp_ipv4_off_list); + mutex_init(&priv->tun.ipv4_off_lock); + INIT_LIST_HEAD(&priv->tun.ipv4_off_list); /* Initialise priv data for neighbour offloading. */ - spin_lock_init(&priv->nfp_neigh_off_lock); - INIT_LIST_HEAD(&priv->nfp_neigh_off_list); - priv->nfp_tun_neigh_nb.notifier_call = nfp_tun_neigh_event_handler; + spin_lock_init(&priv->tun.neigh_off_lock); + INIT_LIST_HEAD(&priv->tun.neigh_off_list); + priv->tun.neigh_nb.notifier_call = nfp_tun_neigh_event_handler; - return register_netevent_notifier(&priv->nfp_tun_neigh_nb); + return register_netevent_notifier(&priv->tun.neigh_nb); } void nfp_tunnel_config_stop(struct nfp_app *app) @@ -690,10 +690,10 @@ void nfp_tunnel_config_stop(struct nfp_app *app) struct nfp_ipv4_addr_entry *ip_entry; struct list_head *ptr, *storage; - unregister_netevent_notifier(&priv->nfp_tun_neigh_nb); + unregister_netevent_notifier(&priv->tun.neigh_nb); /* Free any memory that may be occupied by MAC list. */ - list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) { + list_for_each_safe(ptr, storage, &priv->tun.mac_off_list) { mac_entry = list_entry(ptr, struct nfp_tun_mac_offload_entry, list); list_del(&mac_entry->list); @@ -701,24 +701,24 @@ void nfp_tunnel_config_stop(struct nfp_app *app) } /* Free any memory that may be occupied by MAC index list. */ - list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) { + list_for_each_safe(ptr, storage, &priv->tun.mac_index_list) { mac_idx = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list); list_del(&mac_idx->list); kfree(mac_idx); } - ida_destroy(&priv->nfp_mac_off_ids); + ida_destroy(&priv->tun.mac_off_ids); /* Free any memory that may be occupied by ipv4 list. */ - list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) { + list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) { ip_entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list); list_del(&ip_entry->list); kfree(ip_entry); } /* Free any memory that may be occupied by the route list. */ - list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) { + list_for_each_safe(ptr, storage, &priv->tun.neigh_off_list) { route_entry = list_entry(ptr, struct nfp_ipv4_route_entry, list); list_del(&route_entry->list); -- cgit v1.2.3 From 41da0b5ef3447cf49c3a9dafc9e97a753a785296 Mon Sep 17 00:00:00 2001 From: John Hurley Date: Tue, 15 Jan 2019 19:06:54 -0800 Subject: nfp: flower: ignore offload of VF and PF repr MAC addresses Currently MAC addresses of all repr netdevs, along with selected non-NFP controlled netdevs, are offloaded to FW as potential tunnel end-points. However, the addresses of VF and PF reprs are meaningless outside of internal communication and it is only those of physical port reprs required. Modify the MAC address offload selection code to ignore VF/PF repr devs. Signed-off-by: John Hurley Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 3026ab178fd2..4e509c8c1aca 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -614,11 +614,7 @@ static void nfp_tun_add_to_mac_offload_list(struct net_device *netdev, if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) == NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT) { nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT; - } else if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) == - NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT) { - port = FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC, port); - nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT; - } else { + } else if (!port) { /* Must assign our own unique 8-bit index. */ int idx = nfp_tun_get_mac_idx(app, netdev->ifindex); @@ -628,6 +624,9 @@ static void nfp_tun_add_to_mac_offload_list(struct net_device *netdev, return; } nfp_mac_idx = idx << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT; + } else { + kfree(entry); + return; } entry->index = cpu_to_be16(nfp_mac_idx); -- cgit v1.2.3 From 0115dcc31446adfdce6b37197e988bd4c2b8c6d3 Mon Sep 17 00:00:00 2001 From: John Hurley Date: Tue, 15 Jan 2019 19:06:55 -0800 Subject: nfp: flower: remove list infastructure from MAC offload Potential MAC destination addresses for tunnel end-points are offloaded to firmware. This was done by building a list of such MACs and writing to firmware as blocks of addresses. Simplify this code by removing the list format and sending a new message for each offloaded MAC. This is in preparation for delete MAC messages. There will be one delete flag per message so we cannot assume that this applies to all addresses in a list. Signed-off-by: John Hurley Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.h | 7 - drivers/net/ethernet/netronome/nfp/flower/match.c | 3 - .../ethernet/netronome/nfp/flower/tunnel_conf.c | 159 +++++---------------- 3 files changed, 37 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 977667ae0b5a..1b9d6fd084d8 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -58,29 +58,23 @@ struct nfp_fl_stats_id { /** * struct nfp_fl_tunnel_offloads - priv data for tunnel offloads - * @mac_off_list: List of MAC addresses to offload * @mac_index_list: List of unique 8-bit indexes for non NFP netdevs * @ipv4_off_list: List of IPv4 addresses to offload * @neigh_off_list: List of neighbour offloads - * @mac_off_lock: Lock for the MAC address list * @mac_index_lock: Lock for the MAC index list * @ipv4_off_lock: Lock for the IPv4 address list * @neigh_off_lock: Lock for the neighbour address list * @mac_off_ids: IDA to manage id assignment for offloaded MACs - * @mac_off_count: Number of MACs in address list * @neigh_nb: Notifier to monitor neighbour state */ struct nfp_fl_tunnel_offloads { - struct list_head mac_off_list; struct list_head mac_index_list; struct list_head ipv4_off_list; struct list_head neigh_off_list; - struct mutex mac_off_lock; struct mutex mac_index_lock; struct mutex ipv4_off_lock; spinlock_t neigh_off_lock; struct ida mac_off_ids; - int mac_off_count; struct notifier_block neigh_nb; }; @@ -268,7 +262,6 @@ void nfp_tunnel_config_stop(struct nfp_app *app); int nfp_tunnel_mac_event_handler(struct nfp_app *app, struct net_device *netdev, unsigned long event, void *ptr); -void nfp_tunnel_write_macs(struct nfp_app *app); void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4); void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4); void nfp_tunnel_request_route(struct nfp_app *app, struct sk_buff *skb); diff --git a/drivers/net/ethernet/netronome/nfp/flower/match.c b/drivers/net/ethernet/netronome/nfp/flower/match.c index cdf75595f627..c04a0d6b0184 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/match.c +++ b/drivers/net/ethernet/netronome/nfp/flower/match.c @@ -403,9 +403,6 @@ int nfp_flower_compile_flow_match(struct nfp_app *app, ext += sizeof(struct nfp_flower_ipv4_udp_tun); msk += sizeof(struct nfp_flower_ipv4_udp_tun); - /* Configure tunnel end point MAC. */ - nfp_tunnel_write_macs(app); - /* Store the tunnel destination in the rule data. * This must be present and be an exact match. */ diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 4e509c8c1aca..9b8c73bfcb5b 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -99,32 +99,17 @@ struct nfp_ipv4_addr_entry { }; /** - * struct nfp_tun_mac_addr - configure MAC address of tunnel EP on NFP + * struct nfp_tun_mac_addr_offload - configure MAC address of tunnel EP on NFP * @reserved: reserved for future use - * @count: number of MAC addresses in the message - * @addresses.index: index of MAC address in the lookup table - * @addresses.addr: interface MAC address - * @addresses: series of MACs to offload + * @count: number of MAC addresses in the message (should be 1) + * @index: index of MAC address in the lookup table + * @addr: interface MAC address */ -struct nfp_tun_mac_addr { +struct nfp_tun_mac_addr_offload { __be16 reserved; __be16 count; - struct index_mac_addr { - __be16 index; - u8 addr[ETH_ALEN]; - } addresses[]; -}; - -/** - * struct nfp_tun_mac_offload_entry - list of MACs to offload - * @index: index of MAC address for offloading - * @addr: interface MAC address - * @list: list pointer - */ -struct nfp_tun_mac_offload_entry { __be16 index; u8 addr[ETH_ALEN]; - struct list_head list; }; #define NFP_MAX_MAC_INDEX 0xff @@ -473,64 +458,6 @@ void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4) nfp_tun_write_ipv4_list(app); } -void nfp_tunnel_write_macs(struct nfp_app *app) -{ - struct nfp_flower_priv *priv = app->priv; - struct nfp_tun_mac_offload_entry *entry; - struct nfp_tun_mac_addr *payload; - struct list_head *ptr, *storage; - int mac_count, err, pay_size; - - mutex_lock(&priv->tun.mac_off_lock); - if (!priv->tun.mac_off_count) { - mutex_unlock(&priv->tun.mac_off_lock); - return; - } - - pay_size = sizeof(struct nfp_tun_mac_addr) + - sizeof(struct index_mac_addr) * priv->tun.mac_off_count; - - payload = kzalloc(pay_size, GFP_KERNEL); - if (!payload) { - mutex_unlock(&priv->tun.mac_off_lock); - return; - } - - payload->count = cpu_to_be16(priv->tun.mac_off_count); - - mac_count = 0; - list_for_each_safe(ptr, storage, &priv->tun.mac_off_list) { - entry = list_entry(ptr, struct nfp_tun_mac_offload_entry, - list); - payload->addresses[mac_count].index = entry->index; - ether_addr_copy(payload->addresses[mac_count].addr, - entry->addr); - mac_count++; - } - - err = nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_MAC, - pay_size, payload, GFP_KERNEL); - - kfree(payload); - - if (err) { - mutex_unlock(&priv->tun.mac_off_lock); - /* Write failed so retain list for future retry. */ - return; - } - - /* If list was successfully offloaded, flush it. */ - list_for_each_safe(ptr, storage, &priv->tun.mac_off_list) { - entry = list_entry(ptr, struct nfp_tun_mac_offload_entry, - list); - list_del(&entry->list); - kfree(entry); - } - - priv->tun.mac_off_count = 0; - mutex_unlock(&priv->tun.mac_off_lock); -} - static int nfp_tun_get_mac_idx(struct nfp_app *app, int ifindex) { struct nfp_flower_priv *priv = app->priv; @@ -588,28 +515,35 @@ static void nfp_tun_del_mac_idx(struct nfp_app *app, int ifindex) mutex_unlock(&priv->tun.mac_index_lock); } -static void nfp_tun_add_to_mac_offload_list(struct net_device *netdev, - struct nfp_app *app) +static int __nfp_tunnel_offload_mac(struct nfp_app *app, u8 *mac, u16 idx) +{ + struct nfp_tun_mac_addr_offload payload; + + memset(&payload, 0, sizeof(payload)); + + /* FW supports multiple MACs per cmsg but restrict to single. */ + payload.count = cpu_to_be16(1); + payload.index = cpu_to_be16(idx); + ether_addr_copy(payload.addr, mac); + + return nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_MAC, + sizeof(struct nfp_tun_mac_addr_offload), + &payload, GFP_KERNEL); +} + +static int +nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev) { - struct nfp_flower_priv *priv = app->priv; - struct nfp_tun_mac_offload_entry *entry; u16 nfp_mac_idx; int port = 0; - /* Check if MAC should be offloaded. */ - if (!is_valid_ether_addr(netdev->dev_addr)) - return; - if (nfp_netdev_is_nfp_repr(netdev)) port = nfp_repr_get_port_id(netdev); else if (!nfp_fl_is_netdev_to_offload(netdev)) - return; + return 0; - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - nfp_flower_cmsg_warn(app, "Mem fail when offloading MAC.\n"); - return; - } + if (!is_valid_ether_addr(netdev->dev_addr)) + return -EINVAL; if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) == NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT) { @@ -618,40 +552,33 @@ static void nfp_tun_add_to_mac_offload_list(struct net_device *netdev, /* Must assign our own unique 8-bit index. */ int idx = nfp_tun_get_mac_idx(app, netdev->ifindex); - if (idx < 0) { - nfp_flower_cmsg_warn(app, "Can't assign non-repr MAC index.\n"); - kfree(entry); - return; - } + if (idx < 0) + return idx; + nfp_mac_idx = idx << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT; } else { - kfree(entry); - return; + return 0; } - entry->index = cpu_to_be16(nfp_mac_idx); - ether_addr_copy(entry->addr, netdev->dev_addr); - - mutex_lock(&priv->tun.mac_off_lock); - priv->tun.mac_off_count++; - list_add_tail(&entry->list, &priv->tun.mac_off_list); - mutex_unlock(&priv->tun.mac_off_lock); + return __nfp_tunnel_offload_mac(app, netdev->dev_addr, nfp_mac_idx); } int nfp_tunnel_mac_event_handler(struct nfp_app *app, struct net_device *netdev, unsigned long event, void *ptr) { + int err; + if (event == NETDEV_DOWN || event == NETDEV_UNREGISTER) { /* If non-nfp netdev then free its offload index. */ if (nfp_fl_is_netdev_to_offload(netdev)) nfp_tun_del_mac_idx(app, netdev->ifindex); } else if (event == NETDEV_UP || event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER) { - nfp_tun_add_to_mac_offload_list(netdev, app); - - /* Force a list write to keep NFP up to date. */ - nfp_tunnel_write_macs(app); + err = nfp_tunnel_offload_mac(app, netdev); + if (err) + nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n", + netdev_name(netdev)); } return NOTIFY_OK; } @@ -661,9 +588,6 @@ int nfp_tunnel_config_start(struct nfp_app *app) struct nfp_flower_priv *priv = app->priv; /* Initialise priv data for MAC offloading. */ - priv->tun.mac_off_count = 0; - mutex_init(&priv->tun.mac_off_lock); - INIT_LIST_HEAD(&priv->tun.mac_off_list); mutex_init(&priv->tun.mac_index_lock); INIT_LIST_HEAD(&priv->tun.mac_index_list); ida_init(&priv->tun.mac_off_ids); @@ -682,7 +606,6 @@ int nfp_tunnel_config_start(struct nfp_app *app) void nfp_tunnel_config_stop(struct nfp_app *app) { - struct nfp_tun_mac_offload_entry *mac_entry; struct nfp_flower_priv *priv = app->priv; struct nfp_ipv4_route_entry *route_entry; struct nfp_tun_mac_non_nfp_idx *mac_idx; @@ -691,14 +614,6 @@ void nfp_tunnel_config_stop(struct nfp_app *app) unregister_netevent_notifier(&priv->tun.neigh_nb); - /* Free any memory that may be occupied by MAC list. */ - list_for_each_safe(ptr, storage, &priv->tun.mac_off_list) { - mac_entry = list_entry(ptr, struct nfp_tun_mac_offload_entry, - list); - list_del(&mac_entry->list); - kfree(mac_entry); - } - /* Free any memory that may be occupied by MAC index list. */ list_for_each_safe(ptr, storage, &priv->tun.mac_index_list) { mac_idx = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, -- cgit v1.2.3 From 49402b0b7ff706eba22cb67fe7e2dff9f04ce255 Mon Sep 17 00:00:00 2001 From: John Hurley Date: Tue, 15 Jan 2019 19:06:56 -0800 Subject: nfp: flower: ensure deletion of old offloaded MACs When a potential tunnel end point goes down then its MAC address should not be matchable on the NFP. Implement a delete message for offloaded MACs and call this on net device down. While at it, remove the actions on register and unregister netdev events. A MAC should only be offloaded if the device is up. Note that the netdev notifier will replay any notifications for UP devices on registration so NFP can still offload ports that exist before the driver is loaded. Similarly, devices need to go down before they can be unregistered so removal of offloaded MACs is only required on down events. Signed-off-by: John Hurley Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/flower/tunnel_conf.c | 99 ++++++++++++++++------ 1 file changed, 74 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 9b8c73bfcb5b..46d8a222bd55 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -98,20 +98,27 @@ struct nfp_ipv4_addr_entry { struct list_head list; }; +#define NFP_TUN_MAC_OFFLOAD_DEL_FLAG 0x2 + /** * struct nfp_tun_mac_addr_offload - configure MAC address of tunnel EP on NFP - * @reserved: reserved for future use + * @flags: MAC address offload options * @count: number of MAC addresses in the message (should be 1) * @index: index of MAC address in the lookup table * @addr: interface MAC address */ struct nfp_tun_mac_addr_offload { - __be16 reserved; + __be16 flags; __be16 count; __be16 index; u8 addr[ETH_ALEN]; }; +enum nfp_flower_mac_offload_cmd { + NFP_TUNNEL_MAC_OFFLOAD_ADD = 0, + NFP_TUNNEL_MAC_OFFLOAD_DEL = 1, +}; + #define NFP_MAX_MAC_INDEX 0xff /** @@ -515,12 +522,16 @@ static void nfp_tun_del_mac_idx(struct nfp_app *app, int ifindex) mutex_unlock(&priv->tun.mac_index_lock); } -static int __nfp_tunnel_offload_mac(struct nfp_app *app, u8 *mac, u16 idx) +static int +__nfp_tunnel_offload_mac(struct nfp_app *app, u8 *mac, u16 idx, bool del) { struct nfp_tun_mac_addr_offload payload; memset(&payload, 0, sizeof(payload)); + if (del) + payload.flags = cpu_to_be16(NFP_TUN_MAC_OFFLOAD_DEL_FLAG); + /* FW supports multiple MACs per cmsg but restrict to single. */ payload.count = cpu_to_be16(1); payload.index = cpu_to_be16(idx); @@ -532,22 +543,12 @@ static int __nfp_tunnel_offload_mac(struct nfp_app *app, u8 *mac, u16 idx) } static int -nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev) +nfp_tunnel_get_mac_idx_from_port(struct nfp_app *app, struct net_device *netdev, + int port, u16 *nfp_mac_idx) { - u16 nfp_mac_idx; - int port = 0; - - if (nfp_netdev_is_nfp_repr(netdev)) - port = nfp_repr_get_port_id(netdev); - else if (!nfp_fl_is_netdev_to_offload(netdev)) - return 0; - - if (!is_valid_ether_addr(netdev->dev_addr)) - return -EINVAL; - if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) == NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT) { - nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT; + *nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT; } else if (!port) { /* Must assign our own unique 8-bit index. */ int idx = nfp_tun_get_mac_idx(app, netdev->ifindex); @@ -555,12 +556,58 @@ nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev) if (idx < 0) return idx; - nfp_mac_idx = idx << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT; + *nfp_mac_idx = idx << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT; + } else { + return -EOPNOTSUPP; + } + + return 0; +} + +static int +nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev, + enum nfp_flower_mac_offload_cmd cmd) +{ + bool non_repr = false; + int err, port = 0; + u16 nfp_mac_idx; + + if (nfp_netdev_is_nfp_repr(netdev)) { + struct nfp_repr *repr; + + repr = netdev_priv(netdev); + if (repr->app != app) + return 0; + + port = nfp_repr_get_port_id(netdev); + } else if (nfp_fl_is_netdev_to_offload(netdev)) { + non_repr = true; } else { return 0; } - return __nfp_tunnel_offload_mac(app, netdev->dev_addr, nfp_mac_idx); + if (!is_valid_ether_addr(netdev->dev_addr)) + return -EINVAL; + + switch (cmd) { + case NFP_TUNNEL_MAC_OFFLOAD_ADD: + err = nfp_tunnel_get_mac_idx_from_port(app, netdev, port, + &nfp_mac_idx); + if (err) + return err; + + return __nfp_tunnel_offload_mac(app, netdev->dev_addr, + nfp_mac_idx, false); + case NFP_TUNNEL_MAC_OFFLOAD_DEL: + if (non_repr) + nfp_tun_del_mac_idx(app, netdev->ifindex); + + return __nfp_tunnel_offload_mac(app, netdev->dev_addr, 0, true); + default: + return -EINVAL; + } + + return 0; } int nfp_tunnel_mac_event_handler(struct nfp_app *app, @@ -569,13 +616,15 @@ int nfp_tunnel_mac_event_handler(struct nfp_app *app, { int err; - if (event == NETDEV_DOWN || event == NETDEV_UNREGISTER) { - /* If non-nfp netdev then free its offload index. */ - if (nfp_fl_is_netdev_to_offload(netdev)) - nfp_tun_del_mac_idx(app, netdev->ifindex); - } else if (event == NETDEV_UP || event == NETDEV_CHANGEADDR || - event == NETDEV_REGISTER) { - err = nfp_tunnel_offload_mac(app, netdev); + if (event == NETDEV_DOWN) { + err = nfp_tunnel_offload_mac(app, netdev, + NFP_TUNNEL_MAC_OFFLOAD_DEL); + if (err) + nfp_flower_cmsg_warn(app, "Failed to delete offload MAC on %s.\n", + netdev_name(netdev)); + } else if (event == NETDEV_UP || event == NETDEV_CHANGEADDR) { + err = nfp_tunnel_offload_mac(app, netdev, + NFP_TUNNEL_MAC_OFFLOAD_ADD); if (err) nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n", netdev_name(netdev)); -- cgit v1.2.3 From 05d2bee6bd76164f7d81f3fde83f7461d0ff12af Mon Sep 17 00:00:00 2001 From: John Hurley Date: Tue, 15 Jan 2019 19:06:57 -0800 Subject: nfp: flower: add infastructure for non-repr priv data NFP repr netdevs contain private data that can store per port information. In certain cases, the NFP driver offloads information from non-repr ports (e.g. tunnel ports). As the driver does not have control over non-repr netdevs, it cannot add/track private data directly to the netdev struct. Add infastructure to store private information on any non-repr netdev that is offloaded at a given time. This is used in a following patch to track offloaded MAC addresses for non-reprs and enable correct house keeping on address changes. Signed-off-by: John Hurley Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.c | 66 ++++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/flower/main.h | 22 ++++++++ 2 files changed, 88 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index c370fbcbcc38..837ef0c72f5c 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -32,6 +32,71 @@ static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app) return DEVLINK_ESWITCH_MODE_SWITCHDEV; } +static struct nfp_flower_non_repr_priv * +nfp_flower_non_repr_priv_lookup(struct nfp_app *app, struct net_device *netdev) +{ + struct nfp_flower_priv *priv = app->priv; + struct nfp_flower_non_repr_priv *entry; + + ASSERT_RTNL(); + + list_for_each_entry(entry, &priv->non_repr_priv, list) + if (entry->netdev == netdev) + return entry; + + return NULL; +} + +void +__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv) +{ + non_repr_priv->ref_count++; +} + +struct nfp_flower_non_repr_priv * +nfp_flower_non_repr_priv_get(struct nfp_app *app, struct net_device *netdev) +{ + struct nfp_flower_priv *priv = app->priv; + struct nfp_flower_non_repr_priv *entry; + + entry = nfp_flower_non_repr_priv_lookup(app, netdev); + if (entry) + goto inc_ref; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return NULL; + + entry->netdev = netdev; + list_add(&entry->list, &priv->non_repr_priv); + +inc_ref: + __nfp_flower_non_repr_priv_get(entry); + return entry; +} + +void +__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv) +{ + if (--non_repr_priv->ref_count) + return; + + list_del(&non_repr_priv->list); + kfree(non_repr_priv); +} + +void +nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev) +{ + struct nfp_flower_non_repr_priv *entry; + + entry = nfp_flower_non_repr_priv_lookup(app, netdev); + if (!entry) + return; + + __nfp_flower_non_repr_priv_put(entry); +} + static enum nfp_repr_type nfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port) { @@ -575,6 +640,7 @@ static int nfp_flower_init(struct nfp_app *app) } INIT_LIST_HEAD(&app_priv->indr_block_cb_priv); + INIT_LIST_HEAD(&app_priv->non_repr_priv); return 0; diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 1b9d6fd084d8..2ce898bfc5be 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -145,6 +145,7 @@ struct nfp_fl_lag { * @mtu_conf: Configuration of repr MTU value * @nfp_lag: Link aggregation data block * @indr_block_cb_priv: List of priv data passed to indirect block cbs + * @non_repr_priv: List of offloaded non-repr ports and their priv data * @active_mem_unit: Current active memory unit for flower rules * @total_mem_units: Total number of available memory units for flower rules */ @@ -170,6 +171,7 @@ struct nfp_flower_priv { struct nfp_mtu_conf mtu_conf; struct nfp_fl_lag nfp_lag; struct list_head indr_block_cb_priv; + struct list_head non_repr_priv; unsigned int active_mem_unit; unsigned int total_mem_units; }; @@ -182,6 +184,18 @@ struct nfp_flower_repr_priv { unsigned long lag_port_flags; }; +/** + * struct nfp_flower_non_repr_priv - Priv data for non-repr offloaded ports + * @list: List entry of offloaded reprs + * @netdev: Pointer to non-repr net_device + * @ref_count: Number of references held for this priv data + */ +struct nfp_flower_non_repr_priv { + struct list_head list; + struct net_device *netdev; + int ref_count; +}; + struct nfp_fl_key_ls { u32 key_layer_two; u8 key_layer; @@ -282,4 +296,12 @@ int nfp_flower_reg_indir_block_handler(struct nfp_app *app, struct net_device *netdev, unsigned long event); +void +__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv); +struct nfp_flower_non_repr_priv * +nfp_flower_non_repr_priv_get(struct nfp_app *app, struct net_device *netdev); +void +__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv); +void +nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev); #endif -- cgit v1.2.3 From 13cf71031d797d37bbc960a8260ba47505f6b597 Mon Sep 17 00:00:00 2001 From: John Hurley Date: Tue, 15 Jan 2019 19:06:58 -0800 Subject: nfp: flower: ensure MAC cleanup on address change It is possible to receive a MAC address change notification without the net device being down (e.g. when an OvS bridge is assigned the same MAC as a port added to it). This means that an offloaded MAC address may not be removed if its device gets a new address. Maintain a record of the offloaded MAC addresses for each repr and netdev assigned a MAC offload index. Use this to delete the (now expired) MAC if a change of address event occurs. Only handle change address events if the device is already up - if not then the netdev up event will handle it. Signed-off-by: John Hurley Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.h | 8 ++ .../ethernet/netronome/nfp/flower/tunnel_conf.c | 106 +++++++++++++++++++-- 2 files changed, 104 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 2ce898bfc5be..15b794d0d1e4 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -179,9 +179,13 @@ struct nfp_flower_priv { /** * struct nfp_flower_repr_priv - Flower APP per-repr priv data * @lag_port_flags: Extended port flags to record lag state of repr + * @mac_offloaded: Flag indicating a MAC address is offloaded for repr + * @offloaded_mac_addr: MAC address that has been offloaded for repr */ struct nfp_flower_repr_priv { unsigned long lag_port_flags; + bool mac_offloaded; + u8 offloaded_mac_addr[ETH_ALEN]; }; /** @@ -189,11 +193,15 @@ struct nfp_flower_repr_priv { * @list: List entry of offloaded reprs * @netdev: Pointer to non-repr net_device * @ref_count: Number of references held for this priv data + * @mac_offloaded: Flag indicating a MAC address is offloaded for device + * @offloaded_mac_addr: MAC address that has been offloaded for dev */ struct nfp_flower_non_repr_priv { struct list_head list; struct net_device *netdev; int ref_count; + bool mac_offloaded; + u8 offloaded_mac_addr[ETH_ALEN]; }; struct nfp_fl_key_ls { diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 46d8a222bd55..9d87c88507f3 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -117,6 +117,7 @@ struct nfp_tun_mac_addr_offload { enum nfp_flower_mac_offload_cmd { NFP_TUNNEL_MAC_OFFLOAD_ADD = 0, NFP_TUNNEL_MAC_OFFLOAD_DEL = 1, + NFP_TUNNEL_MAC_OFFLOAD_MOD = 2, }; #define NFP_MAX_MAC_INDEX 0xff @@ -568,46 +569,121 @@ static int nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev, enum nfp_flower_mac_offload_cmd cmd) { - bool non_repr = false; + struct nfp_flower_non_repr_priv *nr_priv = NULL; + bool non_repr = false, *mac_offloaded; + u8 *off_mac = NULL; int err, port = 0; u16 nfp_mac_idx; if (nfp_netdev_is_nfp_repr(netdev)) { + struct nfp_flower_repr_priv *repr_priv; struct nfp_repr *repr; repr = netdev_priv(netdev); if (repr->app != app) return 0; + repr_priv = repr->app_priv; + mac_offloaded = &repr_priv->mac_offloaded; + off_mac = &repr_priv->offloaded_mac_addr[0]; port = nfp_repr_get_port_id(netdev); } else if (nfp_fl_is_netdev_to_offload(netdev)) { + nr_priv = nfp_flower_non_repr_priv_get(app, netdev); + if (!nr_priv) + return -ENOMEM; + + mac_offloaded = &nr_priv->mac_offloaded; + off_mac = &nr_priv->offloaded_mac_addr[0]; non_repr = true; } else { return 0; } - if (!is_valid_ether_addr(netdev->dev_addr)) - return -EINVAL; + if (!is_valid_ether_addr(netdev->dev_addr)) { + err = -EINVAL; + goto err_put_non_repr_priv; + } + + if (cmd == NFP_TUNNEL_MAC_OFFLOAD_MOD && !*mac_offloaded) + cmd = NFP_TUNNEL_MAC_OFFLOAD_ADD; switch (cmd) { case NFP_TUNNEL_MAC_OFFLOAD_ADD: err = nfp_tunnel_get_mac_idx_from_port(app, netdev, port, &nfp_mac_idx); if (err) - return err; + goto err_put_non_repr_priv; + + err = __nfp_tunnel_offload_mac(app, netdev->dev_addr, + nfp_mac_idx, false); + if (err) + goto err_free_mac_idx; - return __nfp_tunnel_offload_mac(app, netdev->dev_addr, - nfp_mac_idx, false); - case NFP_TUNNEL_MAC_OFFLOAD_DEL: if (non_repr) + __nfp_flower_non_repr_priv_get(nr_priv); + + *mac_offloaded = true; + ether_addr_copy(off_mac, netdev->dev_addr); + break; + case NFP_TUNNEL_MAC_OFFLOAD_DEL: + /* Only attempt delete if add was successful. */ + if (!*mac_offloaded) + break; + + if (non_repr) { nfp_tun_del_mac_idx(app, netdev->ifindex); + __nfp_flower_non_repr_priv_put(nr_priv); + } + + *mac_offloaded = false; + + err = __nfp_tunnel_offload_mac(app, netdev->dev_addr, 0, true); + if (err) + goto err_put_non_repr_priv; + + break; + case NFP_TUNNEL_MAC_OFFLOAD_MOD: + /* Ignore if changing to the same address. */ + if (ether_addr_equal(netdev->dev_addr, off_mac)) + break; - return __nfp_tunnel_offload_mac(app, netdev->dev_addr, 0, true); + err = nfp_tunnel_get_mac_idx_from_port(app, netdev, port, + &nfp_mac_idx); + if (err) + goto err_put_non_repr_priv; + + err = __nfp_tunnel_offload_mac(app, netdev->dev_addr, + nfp_mac_idx, false); + if (err) + goto err_put_non_repr_priv; + + /* Delete the previous MAC address. */ + err = __nfp_tunnel_offload_mac(app, off_mac, nfp_mac_idx, + true); + if (err) + nfp_flower_cmsg_warn(app, "Failed to remove offload of replaced MAC addr on %s.\n", + netdev_name(netdev)); + + ether_addr_copy(off_mac, netdev->dev_addr); + break; default: - return -EINVAL; + err = -EINVAL; + goto err_put_non_repr_priv; } + if (non_repr) + __nfp_flower_non_repr_priv_put(nr_priv); + return 0; + +err_free_mac_idx: + if (non_repr) + nfp_tun_del_mac_idx(app, netdev->ifindex); +err_put_non_repr_priv: + if (non_repr) + __nfp_flower_non_repr_priv_put(nr_priv); + + return err; } int nfp_tunnel_mac_event_handler(struct nfp_app *app, @@ -622,12 +698,22 @@ int nfp_tunnel_mac_event_handler(struct nfp_app *app, if (err) nfp_flower_cmsg_warn(app, "Failed to delete offload MAC on %s.\n", netdev_name(netdev)); - } else if (event == NETDEV_UP || event == NETDEV_CHANGEADDR) { + } else if (event == NETDEV_UP) { err = nfp_tunnel_offload_mac(app, netdev, NFP_TUNNEL_MAC_OFFLOAD_ADD); if (err) nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n", netdev_name(netdev)); + } else if (event == NETDEV_CHANGEADDR) { + /* Only offload addr change if netdev is already up. */ + if (!(netdev->flags & IFF_UP)) + return NOTIFY_OK; + + err = nfp_tunnel_offload_mac(app, netdev, + NFP_TUNNEL_MAC_OFFLOAD_MOD); + if (err) + nfp_flower_cmsg_warn(app, "Failed to offload MAC change on %s.\n", + netdev_name(netdev)); } return NOTIFY_OK; } -- cgit v1.2.3 From 20cce88650981ec504d328dbbdd004d991eb8535 Mon Sep 17 00:00:00 2001 From: John Hurley Date: Tue, 15 Jan 2019 19:06:59 -0800 Subject: nfp: flower: enable MAC address sharing for offloadable devs A MAC address is not necessarily a unique identifier for a netdev. Drivers such as Linux bonds, for example, can apply the same MAC address to the upper layer device and all lower layer devices. NFP MAC offload for tunnel decap includes port verification for reprs but also supports the offload of non-repr MAC addresses by assigning 'global' indexes to these. This means that the FW will not verify the incoming port of a packet matching this destination MAC. Modify the MAC offload logic to assign global indexes based on MAC address instead of net device (as it currently does). Use this to allow multiple devices to share the same MAC. In other words, if a repr shares its MAC address with another device then give the offloaded MAC a global index rather than associate it with an ingress port. Track this so that changes can be reverted as MACs stop being shared. Implement this by removing the current list based assignment of global indexes and replacing it with an rhashtable that maps an offloaded MAC address to the number of devices sharing it, distributing global indexes based on this. Signed-off-by: John Hurley Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.c | 2 + drivers/net/ethernet/netronome/nfp/flower/main.h | 10 +- .../ethernet/netronome/nfp/flower/tunnel_conf.c | 343 ++++++++++++++------- 3 files changed, 237 insertions(+), 118 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 837ef0c72f5c..408089133599 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -286,6 +286,7 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app, nfp_repr = netdev_priv(repr); nfp_repr->app_priv = repr_priv; + repr_priv->nfp_repr = nfp_repr; /* For now we only support 1 PF */ WARN_ON(repr_type == NFP_REPR_TYPE_PF && i); @@ -400,6 +401,7 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv) nfp_repr = netdev_priv(repr); nfp_repr->app_priv = repr_priv; + repr_priv->nfp_repr = nfp_repr; port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, repr); if (IS_ERR(port)) { diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 15b794d0d1e4..c0945a5fd1a4 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -58,20 +58,18 @@ struct nfp_fl_stats_id { /** * struct nfp_fl_tunnel_offloads - priv data for tunnel offloads - * @mac_index_list: List of unique 8-bit indexes for non NFP netdevs + * @offloaded_macs: Hashtable of the offloaded MAC addresses * @ipv4_off_list: List of IPv4 addresses to offload * @neigh_off_list: List of neighbour offloads - * @mac_index_lock: Lock for the MAC index list * @ipv4_off_lock: Lock for the IPv4 address list * @neigh_off_lock: Lock for the neighbour address list * @mac_off_ids: IDA to manage id assignment for offloaded MACs * @neigh_nb: Notifier to monitor neighbour state */ struct nfp_fl_tunnel_offloads { - struct list_head mac_index_list; + struct rhashtable offloaded_macs; struct list_head ipv4_off_list; struct list_head neigh_off_list; - struct mutex mac_index_lock; struct mutex ipv4_off_lock; spinlock_t neigh_off_lock; struct ida mac_off_ids; @@ -178,14 +176,18 @@ struct nfp_flower_priv { /** * struct nfp_flower_repr_priv - Flower APP per-repr priv data + * @nfp_repr: Back pointer to nfp_repr * @lag_port_flags: Extended port flags to record lag state of repr * @mac_offloaded: Flag indicating a MAC address is offloaded for repr * @offloaded_mac_addr: MAC address that has been offloaded for repr + * @mac_list: List entry of reprs that share the same offloaded MAC */ struct nfp_flower_repr_priv { + struct nfp_repr *nfp_repr; unsigned long lag_port_flags; bool mac_offloaded; u8 offloaded_mac_addr[ETH_ALEN]; + struct list_head mac_list; }; /** diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 9d87c88507f3..4d78be4ec4e9 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -123,15 +123,26 @@ enum nfp_flower_mac_offload_cmd { #define NFP_MAX_MAC_INDEX 0xff /** - * struct nfp_tun_mac_non_nfp_idx - converts non NFP netdev ifindex to 8-bit id - * @ifindex: netdev ifindex of the device - * @index: index of netdevs mac on NFP - * @list: list pointer + * struct nfp_tun_offloaded_mac - hashtable entry for an offloaded MAC + * @ht_node: Hashtable entry + * @addr: Offloaded MAC address + * @index: Offloaded index for given MAC address + * @ref_count: Number of devs using this MAC address + * @repr_list: List of reprs sharing this MAC address */ -struct nfp_tun_mac_non_nfp_idx { - int ifindex; - u8 index; - struct list_head list; +struct nfp_tun_offloaded_mac { + struct rhash_head ht_node; + u8 addr[ETH_ALEN]; + u16 index; + int ref_count; + struct list_head repr_list; +}; + +static const struct rhashtable_params offloaded_macs_params = { + .key_offset = offsetof(struct nfp_tun_offloaded_mac, addr), + .head_offset = offsetof(struct nfp_tun_offloaded_mac, ht_node), + .key_len = ETH_ALEN, + .automatic_shrinking = true, }; void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb) @@ -466,63 +477,6 @@ void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4) nfp_tun_write_ipv4_list(app); } -static int nfp_tun_get_mac_idx(struct nfp_app *app, int ifindex) -{ - struct nfp_flower_priv *priv = app->priv; - struct nfp_tun_mac_non_nfp_idx *entry; - struct list_head *ptr, *storage; - int idx; - - mutex_lock(&priv->tun.mac_index_lock); - list_for_each_safe(ptr, storage, &priv->tun.mac_index_list) { - entry = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list); - if (entry->ifindex == ifindex) { - idx = entry->index; - mutex_unlock(&priv->tun.mac_index_lock); - return idx; - } - } - - idx = ida_simple_get(&priv->tun.mac_off_ids, 0, - NFP_MAX_MAC_INDEX, GFP_KERNEL); - if (idx < 0) { - mutex_unlock(&priv->tun.mac_index_lock); - return idx; - } - - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - mutex_unlock(&priv->tun.mac_index_lock); - return -ENOMEM; - } - entry->ifindex = ifindex; - entry->index = idx; - list_add_tail(&entry->list, &priv->tun.mac_index_list); - mutex_unlock(&priv->tun.mac_index_lock); - - return idx; -} - -static void nfp_tun_del_mac_idx(struct nfp_app *app, int ifindex) -{ - struct nfp_flower_priv *priv = app->priv; - struct nfp_tun_mac_non_nfp_idx *entry; - struct list_head *ptr, *storage; - - mutex_lock(&priv->tun.mac_index_lock); - list_for_each_safe(ptr, storage, &priv->tun.mac_index_list) { - entry = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list); - if (entry->ifindex == ifindex) { - ida_simple_remove(&priv->tun.mac_off_ids, - entry->index); - list_del(&entry->list); - kfree(entry); - break; - } - } - mutex_unlock(&priv->tun.mac_index_lock); -} - static int __nfp_tunnel_offload_mac(struct nfp_app *app, u8 *mac, u16 idx, bool del) { @@ -543,26 +497,197 @@ __nfp_tunnel_offload_mac(struct nfp_app *app, u8 *mac, u16 idx, bool del) &payload, GFP_KERNEL); } -static int -nfp_tunnel_get_mac_idx_from_port(struct nfp_app *app, struct net_device *netdev, - int port, u16 *nfp_mac_idx) +static bool nfp_tunnel_port_is_phy_repr(int port) { if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) == - NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT) { - *nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT; - } else if (!port) { - /* Must assign our own unique 8-bit index. */ - int idx = nfp_tun_get_mac_idx(app, netdev->ifindex); + NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT) + return true; - if (idx < 0) - return idx; + return false; +} + +static u16 nfp_tunnel_get_mac_idx_from_phy_port_id(int port) +{ + return port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT; +} + +static u16 nfp_tunnel_get_global_mac_idx_from_ida(int id) +{ + return id << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT; +} + +static int nfp_tunnel_get_ida_from_global_mac_idx(u16 nfp_mac_idx) +{ + return nfp_mac_idx >> 8; +} + +static bool nfp_tunnel_is_mac_idx_global(u16 nfp_mac_idx) +{ + return (nfp_mac_idx & 0xff) == NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT; +} + +static struct nfp_tun_offloaded_mac * +nfp_tunnel_lookup_offloaded_macs(struct nfp_app *app, u8 *mac) +{ + struct nfp_flower_priv *priv = app->priv; + + return rhashtable_lookup_fast(&priv->tun.offloaded_macs, mac, + offloaded_macs_params); +} + +static void +nfp_tunnel_offloaded_macs_inc_ref_and_link(struct nfp_tun_offloaded_mac *entry, + struct net_device *netdev, bool mod) +{ + if (nfp_netdev_is_nfp_repr(netdev)) { + struct nfp_flower_repr_priv *repr_priv; + struct nfp_repr *repr; + + repr = netdev_priv(netdev); + repr_priv = repr->app_priv; - *nfp_mac_idx = idx << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT; + /* If modifing MAC, remove repr from old list first. */ + if (mod) + list_del(&repr_priv->mac_list); + + list_add_tail(&repr_priv->mac_list, &entry->repr_list); + } + + entry->ref_count++; +} + +static int +nfp_tunnel_add_shared_mac(struct nfp_app *app, struct net_device *netdev, + int port, bool mod) +{ + struct nfp_flower_priv *priv = app->priv; + int ida_idx = NFP_MAX_MAC_INDEX, err; + struct nfp_tun_offloaded_mac *entry; + u16 nfp_mac_idx = 0; + + entry = nfp_tunnel_lookup_offloaded_macs(app, netdev->dev_addr); + if (entry && nfp_tunnel_is_mac_idx_global(entry->index)) { + nfp_tunnel_offloaded_macs_inc_ref_and_link(entry, netdev, mod); + return 0; + } + + /* Assign a global index if non-repr or MAC address is now shared. */ + if (entry || !port) { + ida_idx = ida_simple_get(&priv->tun.mac_off_ids, 0, + NFP_MAX_MAC_INDEX, GFP_KERNEL); + if (ida_idx < 0) + return ida_idx; + + nfp_mac_idx = nfp_tunnel_get_global_mac_idx_from_ida(ida_idx); } else { - return -EOPNOTSUPP; + nfp_mac_idx = nfp_tunnel_get_mac_idx_from_phy_port_id(port); + } + + if (!entry) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + err = -ENOMEM; + goto err_free_ida; + } + + ether_addr_copy(entry->addr, netdev->dev_addr); + INIT_LIST_HEAD(&entry->repr_list); + + if (rhashtable_insert_fast(&priv->tun.offloaded_macs, + &entry->ht_node, + offloaded_macs_params)) { + err = -ENOMEM; + goto err_free_entry; + } } + err = __nfp_tunnel_offload_mac(app, netdev->dev_addr, + nfp_mac_idx, false); + if (err) { + /* If not shared then free. */ + if (!entry->ref_count) + goto err_remove_hash; + goto err_free_ida; + } + + entry->index = nfp_mac_idx; + nfp_tunnel_offloaded_macs_inc_ref_and_link(entry, netdev, mod); + return 0; + +err_remove_hash: + rhashtable_remove_fast(&priv->tun.offloaded_macs, &entry->ht_node, + offloaded_macs_params); +err_free_entry: + kfree(entry); +err_free_ida: + if (ida_idx != NFP_MAX_MAC_INDEX) + ida_simple_remove(&priv->tun.mac_off_ids, ida_idx); + + return err; +} + +static int +nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev, + u8 *mac, bool mod) +{ + struct nfp_flower_priv *priv = app->priv; + struct nfp_flower_repr_priv *repr_priv; + struct nfp_tun_offloaded_mac *entry; + struct nfp_repr *repr; + int ida_idx; + + entry = nfp_tunnel_lookup_offloaded_macs(app, mac); + if (!entry) + return 0; + + entry->ref_count--; + /* If del is part of a mod then mac_list is still in use elsewheree. */ + if (nfp_netdev_is_nfp_repr(netdev) && !mod) { + repr = netdev_priv(netdev); + repr_priv = repr->app_priv; + list_del(&repr_priv->mac_list); + } + + /* If MAC is now used by 1 repr set the offloaded MAC index to port. */ + if (entry->ref_count == 1 && list_is_singular(&entry->repr_list)) { + u16 nfp_mac_idx; + int port, err; + + repr_priv = list_first_entry(&entry->repr_list, + struct nfp_flower_repr_priv, + mac_list); + repr = repr_priv->nfp_repr; + port = nfp_repr_get_port_id(repr->netdev); + nfp_mac_idx = nfp_tunnel_get_mac_idx_from_phy_port_id(port); + err = __nfp_tunnel_offload_mac(app, mac, nfp_mac_idx, false); + if (err) { + nfp_flower_cmsg_warn(app, "MAC offload index revert failed on %s.\n", + netdev_name(netdev)); + return 0; + } + + ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index); + ida_simple_remove(&priv->tun.mac_off_ids, ida_idx); + entry->index = nfp_mac_idx; + return 0; + } + + if (entry->ref_count) + return 0; + + WARN_ON_ONCE(rhashtable_remove_fast(&priv->tun.offloaded_macs, + &entry->ht_node, + offloaded_macs_params)); + /* If MAC has global ID then extract and free the ida entry. */ + if (nfp_tunnel_is_mac_idx_global(entry->index)) { + ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index); + ida_simple_remove(&priv->tun.mac_off_ids, ida_idx); + } + + kfree(entry); + + return __nfp_tunnel_offload_mac(app, mac, 0, true); } static int @@ -573,7 +698,6 @@ nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev, bool non_repr = false, *mac_offloaded; u8 *off_mac = NULL; int err, port = 0; - u16 nfp_mac_idx; if (nfp_netdev_is_nfp_repr(netdev)) { struct nfp_flower_repr_priv *repr_priv; @@ -587,6 +711,8 @@ nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev, mac_offloaded = &repr_priv->mac_offloaded; off_mac = &repr_priv->offloaded_mac_addr[0]; port = nfp_repr_get_port_id(netdev); + if (!nfp_tunnel_port_is_phy_repr(port)) + return 0; } else if (nfp_fl_is_netdev_to_offload(netdev)) { nr_priv = nfp_flower_non_repr_priv_get(app, netdev); if (!nr_priv) @@ -609,16 +735,10 @@ nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev, switch (cmd) { case NFP_TUNNEL_MAC_OFFLOAD_ADD: - err = nfp_tunnel_get_mac_idx_from_port(app, netdev, port, - &nfp_mac_idx); + err = nfp_tunnel_add_shared_mac(app, netdev, port, false); if (err) goto err_put_non_repr_priv; - err = __nfp_tunnel_offload_mac(app, netdev->dev_addr, - nfp_mac_idx, false); - if (err) - goto err_free_mac_idx; - if (non_repr) __nfp_flower_non_repr_priv_get(nr_priv); @@ -630,14 +750,13 @@ nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev, if (!*mac_offloaded) break; - if (non_repr) { - nfp_tun_del_mac_idx(app, netdev->ifindex); + if (non_repr) __nfp_flower_non_repr_priv_put(nr_priv); - } *mac_offloaded = false; - err = __nfp_tunnel_offload_mac(app, netdev->dev_addr, 0, true); + err = nfp_tunnel_del_shared_mac(app, netdev, netdev->dev_addr, + false); if (err) goto err_put_non_repr_priv; @@ -647,19 +766,12 @@ nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev, if (ether_addr_equal(netdev->dev_addr, off_mac)) break; - err = nfp_tunnel_get_mac_idx_from_port(app, netdev, port, - &nfp_mac_idx); - if (err) - goto err_put_non_repr_priv; - - err = __nfp_tunnel_offload_mac(app, netdev->dev_addr, - nfp_mac_idx, false); + err = nfp_tunnel_add_shared_mac(app, netdev, port, true); if (err) goto err_put_non_repr_priv; /* Delete the previous MAC address. */ - err = __nfp_tunnel_offload_mac(app, off_mac, nfp_mac_idx, - true); + err = nfp_tunnel_del_shared_mac(app, netdev, off_mac, true); if (err) nfp_flower_cmsg_warn(app, "Failed to remove offload of replaced MAC addr on %s.\n", netdev_name(netdev)); @@ -676,9 +788,6 @@ nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev, return 0; -err_free_mac_idx: - if (non_repr) - nfp_tun_del_mac_idx(app, netdev->ifindex); err_put_non_repr_priv: if (non_repr) __nfp_flower_non_repr_priv_put(nr_priv); @@ -721,10 +830,14 @@ int nfp_tunnel_mac_event_handler(struct nfp_app *app, int nfp_tunnel_config_start(struct nfp_app *app) { struct nfp_flower_priv *priv = app->priv; + int err; + + /* Initialise rhash for MAC offload tracking. */ + err = rhashtable_init(&priv->tun.offloaded_macs, + &offloaded_macs_params); + if (err) + return err; - /* Initialise priv data for MAC offloading. */ - mutex_init(&priv->tun.mac_index_lock); - INIT_LIST_HEAD(&priv->tun.mac_index_list); ida_init(&priv->tun.mac_off_ids); /* Initialise priv data for IPv4 offloading. */ @@ -736,27 +849,25 @@ int nfp_tunnel_config_start(struct nfp_app *app) INIT_LIST_HEAD(&priv->tun.neigh_off_list); priv->tun.neigh_nb.notifier_call = nfp_tun_neigh_event_handler; - return register_netevent_notifier(&priv->tun.neigh_nb); + err = register_netevent_notifier(&priv->tun.neigh_nb); + if (err) { + rhashtable_free_and_destroy(&priv->tun.offloaded_macs, + nfp_check_rhashtable_empty, NULL); + return err; + } + + return 0; } void nfp_tunnel_config_stop(struct nfp_app *app) { struct nfp_flower_priv *priv = app->priv; struct nfp_ipv4_route_entry *route_entry; - struct nfp_tun_mac_non_nfp_idx *mac_idx; struct nfp_ipv4_addr_entry *ip_entry; struct list_head *ptr, *storage; unregister_netevent_notifier(&priv->tun.neigh_nb); - /* Free any memory that may be occupied by MAC index list. */ - list_for_each_safe(ptr, storage, &priv->tun.mac_index_list) { - mac_idx = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, - list); - list_del(&mac_idx->list); - kfree(mac_idx); - } - ida_destroy(&priv->tun.mac_off_ids); /* Free any memory that may be occupied by ipv4 list. */ @@ -773,4 +884,8 @@ void nfp_tunnel_config_stop(struct nfp_app *app) list_del(&route_entry->list); kfree(route_entry); } + + /* Destroy rhash. Entries should be cleaned on netdev notifier unreg. */ + rhashtable_free_and_destroy(&priv->tun.offloaded_macs, + nfp_check_rhashtable_empty, NULL); } -- cgit v1.2.3 From 1868e3d72236cbaf92c99b89f0bc0d8bdb0c47d4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 15 Jan 2019 21:11:14 +0100 Subject: net: phy: remove preliminary workaround for not loading PHY driver This workaround attempt helped for some but not all affected users. With commit 11287b693d03 ("r8169: load Realtek PHY driver module before r8169") we have a better workaround now, so we an remove the first attempt. Signed-off-by: Heiner Kallweit Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 51990002d495..a2423cbb218d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2250,14 +2250,6 @@ int phy_driver_register(struct phy_driver *new_driver, struct module *owner) new_driver->mdiodrv.driver.remove = phy_remove; new_driver->mdiodrv.driver.owner = owner; - /* The following works around an issue where the PHY driver doesn't bind - * to the device, resulting in the genphy driver being used instead of - * the dedicated driver. The root cause of the issue isn't known yet - * and seems to be in the base driver core. Once this is fixed we may - * remove this workaround. - */ - new_driver->mdiodrv.driver.probe_type = PROBE_FORCE_SYNCHRONOUS; - retval = driver_register(&new_driver->mdiodrv.driver); if (retval) { pr_err("%s: Error %d in registering driver\n", -- cgit v1.2.3 From c3a6a174d53918b810b60b2bf3e7a46c9a0a19eb Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 15 Jan 2019 21:50:25 +0100 Subject: net: phy: improve logging in phylib Some time ago phydev_info() and friends have been added. They allow to improve and simplify logging. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 5 +---- drivers/net/phy/phy_device.c | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d33e7b3caf03..c0802d4d084e 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -13,8 +13,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -814,8 +812,7 @@ int phy_start_interrupts(struct phy_device *phydev) if (request_threaded_irq(phydev->irq, NULL, phy_interrupt, IRQF_ONESHOT | IRQF_SHARED, phydev_name(phydev), phydev) < 0) { - pr_warn("%s: Can't get IRQ %d (PHY)\n", - phydev->mdio.bus->name, phydev->irq); + phydev_warn(phydev, "Can't get IRQ %d\n", phydev->irq); phydev->irq = PHY_POLL; return 0; } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index a2423cbb218d..1c7fe7a4c970 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -819,13 +819,13 @@ int phy_device_register(struct phy_device *phydev) /* Run all of the fixups for this PHY */ err = phy_scan_fixups(phydev); if (err) { - pr_err("PHY %d failed to initialize\n", phydev->mdio.addr); + phydev_err(phydev, "failed to initialize\n"); goto out; } err = device_add(&phydev->mdio.dev); if (err) { - pr_err("PHY %d failed to add\n", phydev->mdio.addr); + phydev_err(phydev, "failed to add\n"); goto out; } -- cgit v1.2.3 From 3fcb3f9b68b048d6b44d5cfabe21ee3145b90424 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 15 Jan 2019 21:40:51 +0100 Subject: net: phy: don't include asm/irq.h directly There's no need to and one shouldn't include asm/irq.h directly. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 2 -- drivers/net/phy/phy.c | 2 -- drivers/net/phy/phy_device.c | 2 -- 3 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 2e59a8419b17..741f27228088 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -39,8 +39,6 @@ #include #include -#include - #define CREATE_TRACE_POINTS #include diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c0802d4d084e..241fb83ef4de 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -34,8 +34,6 @@ #include #include -#include - #define PHY_STATE_STR(_state) \ case PHY_##_state: \ return __stringify(_state); \ diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1c7fe7a4c970..bb1410821ce4 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -37,8 +37,6 @@ #include #include -#include - MODULE_DESCRIPTION("PHY library"); MODULE_AUTHOR("Andy Fleming"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 78c787c21f974fe87a9c4418f57a5f76ba880608 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 15 Jan 2019 15:44:52 -0600 Subject: cxgb4/l2t: Use struct_size() in kvzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; struct boo entry[]; }; instance = kvzalloc(sizeof(struct foo) + count * sizeof(struct boo), GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kvzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 4852febbfec3..1a407d3c1d67 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -646,7 +646,7 @@ struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end) if (l2t_size < L2T_MIN_HASH_BUCKETS) return NULL; - d = kvzalloc(sizeof(*d) + l2t_size * sizeof(struct l2t_entry), GFP_KERNEL); + d = kvzalloc(struct_size(d, l2tab, l2t_size), GFP_KERNEL); if (!d) return NULL; -- cgit v1.2.3 From fcd44b64b1eb0a33f6cc14f21dcb927ffd664af3 Mon Sep 17 00:00:00 2001 From: Yogesh Narayan Gaur Date: Tue, 15 Jan 2019 10:05:10 +0000 Subject: mtd: spi-nor: add opcodes for octal Read/Write commands - Add opcodes for octal I/O commands * Read : 1-1-8 and 1-8-8 protocol * Write : 1-1-8 and 1-8-8 protocol * opcodes for 4-byte address mode command - Entry of macros in _convert_3to4_xxx function - Add flag SPI_NOR_OCTAL_READ specifying flash support octal read commands. This flag is required for flashes which didn't provides support for auto detection of Octal mode capabilities i.e. not seems to support newer JESD216C standard. Signed-off-by: Vignesh R Signed-off-by: Yogesh Narayan Gaur Reviewed-by: Tudor Ambarus Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 6e13bbd1aaa5..872d70722672 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -68,7 +68,7 @@ enum spi_nor_read_command_index { SNOR_CMD_READ_4_4_4, SNOR_CMD_READ_1_4_4_DTR, - /* Octo SPI */ + /* Octal SPI */ SNOR_CMD_READ_1_1_8, SNOR_CMD_READ_1_8_8, SNOR_CMD_READ_8_8_8, @@ -85,7 +85,7 @@ enum spi_nor_pp_command_index { SNOR_CMD_PP_1_4_4, SNOR_CMD_PP_4_4_4, - /* Octo SPI */ + /* Octal SPI */ SNOR_CMD_PP_1_1_8, SNOR_CMD_PP_1_8_8, SNOR_CMD_PP_8_8_8, @@ -278,6 +278,7 @@ struct flash_info { #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define USE_CLSR BIT(14) /* use CLSR command */ +#define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */ /* Part specific fixup hooks. */ const struct spi_nor_fixups *fixups; @@ -398,6 +399,8 @@ static u8 spi_nor_convert_3to4_read(u8 opcode) { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B }, { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B }, { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B }, + { SPINOR_OP_READ_1_1_8, SPINOR_OP_READ_1_1_8_4B }, + { SPINOR_OP_READ_1_8_8, SPINOR_OP_READ_1_8_8_4B }, { SPINOR_OP_READ_1_1_1_DTR, SPINOR_OP_READ_1_1_1_DTR_4B }, { SPINOR_OP_READ_1_2_2_DTR, SPINOR_OP_READ_1_2_2_DTR_4B }, @@ -414,6 +417,8 @@ static u8 spi_nor_convert_3to4_program(u8 opcode) { SPINOR_OP_PP, SPINOR_OP_PP_4B }, { SPINOR_OP_PP_1_1_4, SPINOR_OP_PP_1_1_4_4B }, { SPINOR_OP_PP_1_4_4, SPINOR_OP_PP_1_4_4_4B }, + { SPINOR_OP_PP_1_1_8, SPINOR_OP_PP_1_1_8_4B }, + { SPINOR_OP_PP_1_8_8, SPINOR_OP_PP_1_8_8_4B }, }; return spi_nor_convert_opcode(opcode, spi_nor_3to4_program, @@ -3591,6 +3596,13 @@ static int spi_nor_init_params(struct spi_nor *nor, SNOR_PROTO_1_1_4); } + if (info->flags & SPI_NOR_OCTAL_READ) { + params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8; + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_8], + 0, 8, SPINOR_OP_READ_1_1_8, + SNOR_PROTO_1_1_8); + } + /* Page Program settings. */ params->hwcaps.mask |= SNOR_HWCAPS_PP; spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], -- cgit v1.2.3 From 2bda2f811b36cb7e569ca384e2dfcf74740a8279 Mon Sep 17 00:00:00 2001 From: Yogesh Narayan Gaur Date: Tue, 15 Jan 2019 10:05:16 +0000 Subject: mtd: spi-nor: add octal read flag for flash mt35xu512aba Add octal read flag for flash mt35xu512aba. This flash, mt35xu512aba, is only complaint to SFDP JESD216B and does not seem to support newer JESD216C standard that provides auto detection of Octal mode capabilities and opcodes. Therefore, this capability is manually added using new SPI_NOR_OCTAL_READ flag. Signed-off-by: Vignesh R Signed-off-by: Yogesh Narayan Gaur Reviewed-by: Tudor Ambarus Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 872d70722672..53a3bcc6a55b 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1877,7 +1877,8 @@ static const struct flash_info spi_nor_ids[] = { /* Micron */ { "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512, - SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES) + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | + SPI_NOR_4B_OPCODES) }, /* PMC */ -- cgit v1.2.3 From 0837ae46ff003fed44bfead23c590e7105f47623 Mon Sep 17 00:00:00 2001 From: Yogesh Narayan Gaur Date: Tue, 15 Jan 2019 10:05:22 +0000 Subject: mtd: m25p80: add support of octal mode I/O transfer Add support for octal mode I/O data transfer based on the controller (spi) mode. Assign hw-capability mask bits for octal transfer. Signed-off-by: Yogesh Narayan Gaur Reviewed-by: Tudor Ambarus Signed-off-by: Boris Brezillon --- drivers/mtd/devices/m25p80.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index c4a1d04b8c80..651bab6d4e31 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -195,7 +195,14 @@ static int m25p_probe(struct spi_mem *spimem) spi_mem_set_drvdata(spimem, flash); flash->spimem = spimem; - if (spi->mode & SPI_RX_QUAD) { + if (spi->mode & SPI_RX_OCTAL) { + hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8; + + if (spi->mode & SPI_TX_OCTAL) + hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 | + SNOR_HWCAPS_PP_1_1_8 | + SNOR_HWCAPS_PP_1_8_8); + } else if (spi->mode & SPI_RX_QUAD) { hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; if (spi->mode & SPI_TX_QUAD) -- cgit v1.2.3 From a666f2619a97ab9264d3b06055a336b3ee75c108 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Wed, 16 Jan 2019 19:55:44 +0100 Subject: spi: bitbang: Don't call chipselect() in spi_bitbang_setup() spi_setup() already call spi_set_cs() right after calling the controller setup method, so there is no need for the bitbang driver to do that. Because of this the chipselect() callback was confusingly still called when CS is GPIO based. Signed-off-by: Alban Bedel Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index f29176000b8d..dd9a8c54a693 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -213,19 +213,6 @@ int spi_bitbang_setup(struct spi_device *spi) dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); - /* NOTE we _need_ to call chipselect() early, ideally with adapter - * setup, unless the hardware defaults cooperate to avoid confusion - * between normal (active low) and inverted chipselects. - */ - - /* deselect chip (low or high) */ - mutex_lock(&bitbang->lock); - if (!bitbang->busy) { - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(cs->nsecs); - } - mutex_unlock(&bitbang->lock); - return 0; } EXPORT_SYMBOL_GPL(spi_bitbang_setup); -- cgit v1.2.3 From 797622d7a3ab5192ff575288bdbec15c3a006280 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Wed, 16 Jan 2019 19:55:45 +0100 Subject: spi: ath79: Simplify ath79_spi_chipselect() First of all this callback was slightly misused to setup the clock polarity at the beginning of a transfer. Beside being at the wrong place, it is also useless as only SPI mode 1 is supported. Instead just make sure the base value used for IOC is suitable to start a transfer by clearing the clock and data bits during the controller setup. This also remove the last direct usage of the GPIO API, so we can remove the direct dependency on GPIOLIB. Signed-off-by: Alban Bedel Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- drivers/spi/spi-ath79.c | 40 +++++++++------------------------------- 2 files changed, 10 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index dc67eda1788a..128892c7e21e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -63,7 +63,7 @@ config SPI_ALTERA config SPI_ATH79 tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" - depends on ATH79 && GPIOLIB + depends on ATH79 select SPI_BITBANG help This enables support for the SPI controller present on the diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index ed1068ac055f..edf695a359f4 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -67,38 +66,14 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active) { struct ath79_spi *sp = ath79_spidev_to_sp(spi); int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active; + u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); - if (is_active) { - /* set initial clock polarity */ - if (spi->mode & SPI_CPOL) - sp->ioc_base |= AR71XX_SPI_IOC_CLK; - else - sp->ioc_base &= ~AR71XX_SPI_IOC_CLK; - - ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); - } - - if (spi->cs_gpiod) { - /* - * SPI chipselect is normally active-low, but - * inversion semantics are handled by gpiolib. - * - * FIXME: is this ever used? The driver doesn't - * set SPI_MASTER_GPIO_SS so this callback should not - * get called if a CS GPIO is found by the SPI core. - */ - gpiod_set_value_cansleep(spi->cs_gpiod, is_active); - } else { - u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); - - if (cs_high) - sp->ioc_base |= cs_bit; - else - sp->ioc_base &= ~cs_bit; - - ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); - } + if (cs_high) + sp->ioc_base |= cs_bit; + else + sp->ioc_base &= ~cs_bit; + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } static void ath79_spi_enable(struct ath79_spi *sp) @@ -110,6 +85,9 @@ static void ath79_spi_enable(struct ath79_spi *sp) sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL); sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC); + /* clear clk and mosi in the base state */ + sp->ioc_base &= ~(AR71XX_SPI_IOC_DO | AR71XX_SPI_IOC_CLK); + /* TODO: setup speed? */ ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43); } -- cgit v1.2.3 From b172fd0c898022c47161a99cb40be5304b0d3fd0 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Wed, 16 Jan 2019 19:55:46 +0100 Subject: spi: ath79: Enable support for compile test To allow building this driver in compile test we need to remove all dependency on headers from arch/mips/include. To allow this we explicitly define all the registers locally instead of using ar71xx_regs.h and we move the platform data struct definition to include/linux/platform_data/spi-ath79.h. Signed-off-by: Alban Bedel Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- drivers/spi/spi-ath79.c | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 128892c7e21e..71d3d2d5e5d1 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -63,7 +63,7 @@ config SPI_ALTERA config SPI_ATH79 tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" - depends on ATH79 + depends on ATH79 || COMPILE_TEST select SPI_BITBANG help This enables support for the SPI controller present on the diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index edf695a359f4..09c4fb7fcf7a 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -23,15 +23,24 @@ #include #include #include - -#include -#include +#include #define DRV_NAME "ath79-spi" #define ATH79_SPI_RRW_DELAY_FACTOR 12000 #define MHZ (1000 * 1000) +#define AR71XX_SPI_REG_FS 0x00 /* Function Select */ +#define AR71XX_SPI_REG_CTRL 0x04 /* SPI Control */ +#define AR71XX_SPI_REG_IOC 0x08 /* SPI I/O Control */ +#define AR71XX_SPI_REG_RDS 0x0c /* Read Data Shift */ + +#define AR71XX_SPI_FS_GPIO BIT(0) /* Enable GPIO mode */ + +#define AR71XX_SPI_IOC_DO BIT(0) /* Data Out pin */ +#define AR71XX_SPI_IOC_CLK BIT(8) /* CLK pin */ +#define AR71XX_SPI_IOC_CS(n) BIT(16 + (n)) + struct ath79_spi { struct spi_bitbang bitbang; u32 ioc_base; -- cgit v1.2.3 From f1b2c1c84f7f04d91749e1550f24510c6b6eac73 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Wed, 16 Jan 2019 19:55:47 +0100 Subject: spi: ath79: Remove now useless code The custom setup/cleanup routines included in the ath79 driver only take care of setting the initial CS state. However that is already handled by the bitbang code, so this code can be removed. Signed-off-by: Alban Bedel Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 43 ++----------------------------------------- 1 file changed, 2 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 09c4fb7fcf7a..847f354ebef1 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -109,44 +109,6 @@ static void ath79_spi_disable(struct ath79_spi *sp) ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0); } -static int ath79_spi_setup_cs(struct spi_device *spi) -{ - struct ath79_spi *sp = ath79_spidev_to_sp(spi); - - if (!spi->cs_gpiod) { - u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); - - if (spi->mode & SPI_CS_HIGH) - sp->ioc_base &= ~cs_bit; - else - sp->ioc_base |= cs_bit; - - ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); - } - - return 0; -} - -static int ath79_spi_setup(struct spi_device *spi) -{ - int status = 0; - - if (!spi->controller_state) { - status = ath79_spi_setup_cs(spi); - if (status) - return status; - } - - status = spi_bitbang_setup(spi); - - return status; -} - -static void ath79_spi_cleanup(struct spi_device *spi) -{ - spi_bitbang_cleanup(spi); -} - static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs, u32 word, u8 bits, unsigned flags) { @@ -199,8 +161,8 @@ static int ath79_spi_probe(struct platform_device *pdev) master->use_gpio_descriptors = true; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); - master->setup = ath79_spi_setup; - master->cleanup = ath79_spi_cleanup; + master->setup = spi_bitbang_setup; + master->cleanup = spi_bitbang_cleanup; if (pdata) { master->bus_num = pdata->bus_num; master->num_chipselect = pdata->num_chipselect; @@ -209,7 +171,6 @@ static int ath79_spi_probe(struct platform_device *pdev) sp->bitbang.master = master; sp->bitbang.chipselect = ath79_spi_chipselect; sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0; - sp->bitbang.setup_transfer = spi_bitbang_setup_transfer; sp->bitbang.flags = SPI_CS_HIGH; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3 From 013b2dff8153b4c01d2179dbefec6b9108383802 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 11 Jan 2019 13:37:43 +0100 Subject: mt76: fix tx status reporting for non-probing frames On MT76x2, the hardware does not report tx status in the FIFO register, if the packet id is 0. Change the allocation of packet IDs to use 0 for no-ack packets, 1 for non-probing packets and 2-255 for packets with tx status requested. Fixes rate control issues Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 +++- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 3 +-- drivers/net/wireless/mediatek/mt76/tx.c | 9 +++++---- 5 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8ef430d8afc4..8d56ab97abe3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -239,7 +239,9 @@ struct mt76_rx_tid { #define MT_TX_CB_TXS_FAILED BIT(2) #define MT_PACKET_ID_MASK GENMASK(7, 0) -#define MT_PACKET_ID_NO_ACK MT_PACKET_ID_MASK +#define MT_PACKET_ID_NO_ACK 0 +#define MT_PACKET_ID_NO_SKB 1 +#define MT_PACKET_ID_FIRST 2 #define MT_TX_STATUS_SKB_TIMEOUT HZ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 6adea0278284..38cd77d30f5c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -433,7 +433,7 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, } if (wcid) { - if (stat->pktid) + if (stat->pktid >= MT_PACKET_ID_FIRST) status.skb = mt76_tx_status_skb_get(mdev, wcid, stat->pktid, &list); if (status.skb) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index 4598cb2cc3ff..a5413a309a0a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -177,7 +177,7 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (ret < 0) return ret; - if (pid && pid != MT_PACKET_ID_NO_ACK) + if (pid >= MT_PACKET_ID_FIRST) qsel = MT_QSEL_MGMT; *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 81970cf777c0..098d05e109e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -87,8 +87,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, pid = mt76_tx_status_skb_add(mdev, wcid, skb); txwi->pktid = pid; - if ((pid && pid != MT_PACKET_ID_NO_ACK) || - q2ep(q->hw_idx) == MT_EP_OUT_HCCA) + if (pid >= MT_PACKET_ID_FIRST || q2ep(q->hw_idx) == MT_EP_OUT_HCCA) qsel = MT_QSEL_MGMT; else qsel = MT_QSEL_EDCA; diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index f08509c1670d..1ea08ce62713 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -170,21 +170,22 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, int pid; if (!wcid) - return 0; + return MT_PACKET_ID_NO_ACK; if (info->flags & IEEE80211_TX_CTL_NO_ACK) return MT_PACKET_ID_NO_ACK; if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | IEEE80211_TX_CTL_RATE_CTRL_PROBE))) - return 0; + return MT_PACKET_ID_NO_SKB; spin_lock_bh(&dev->status_list.lock); memset(cb, 0, sizeof(*cb)); wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; - if (!wcid->packet_id || wcid->packet_id == MT_PACKET_ID_NO_ACK) - wcid->packet_id = 1; + if (wcid->packet_id == MT_PACKET_ID_NO_ACK || + wcid->packet_id == MT_PACKET_ID_NO_SKB) + wcid->packet_id = MT_PACKET_ID_FIRST; pid = wcid->packet_id; cb->wcid = wcid->idx; -- cgit v1.2.3 From f545540d5f6007def13cf235a914891b67693828 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 16 Jan 2019 22:33:18 +0100 Subject: mt76: set IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR flag The hardware does not deal with multiple WCID entries for the same station properly. Set IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR to avoid those cases Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 7b926dfa6b97..3d976ac4cb41 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -328,6 +328,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); wiphy->flags |= WIPHY_FLAG_IBSS_RSN; -- cgit v1.2.3 From 9313faacbb4eeb03799a86cd013e97409a40b970 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 6 Dec 2018 14:27:34 +0100 Subject: mt76: move mt76x02_get_txpower to mt76 core It will be reused by mt7603 later Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 18 ++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 -- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 18 ------------------ drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 2 +- 8 files changed, 25 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 3d976ac4cb41..467b5a692ed1 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -710,3 +710,21 @@ int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } EXPORT_SYMBOL_GPL(mt76_sta_state); + +int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int *dbm) +{ + struct mt76_dev *dev = hw->priv; + int n_chains = __sw_hweight8(dev->antenna_mask); + + *dbm = dev->txpower_cur / 2; + + /* convert from per-chain power to combined + * output on 2x2 devices + */ + if (n_chains > 1) + *dbm += 3; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_get_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8d56ab97abe3..16b342f63d29 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -680,6 +680,9 @@ int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb); +int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int *dbm); + /* internal */ void mt76_tx_free(struct mt76_dev *dev); struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 720b05e325a5..1472c8699b29 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -99,7 +99,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .wake_tx_queue = mt76_wake_tx_queue, .get_survey = mt76_get_survey, - .get_txpower = mt76x02_get_txpower, + .get_txpower = mt76_get_txpower, .flush = mt76x0e_flush, .set_tim = mt76x0e_set_tim, .release_buffered_frames = mt76_release_buffered_frames, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 0e6b43bb4678..f66e1b2f0980 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -155,7 +155,7 @@ static const struct ieee80211_ops mt76x0u_ops = { .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .set_rts_threshold = mt76x02_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, - .get_txpower = mt76x02_get_txpower, + .get_txpower = mt76_get_txpower, }; static int mt76x0u_register_device(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index d8bd0509a790..6d96766a6ed3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -172,8 +172,6 @@ void mt76x02_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac); void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int mt76x02_get_txpower(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int *dbm); void mt76x02_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x02_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index d80c8eb5a0ec..59f50a957cd5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -607,24 +607,6 @@ void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete); -int mt76x02_get_txpower(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int *dbm) -{ - struct mt76x02_dev *dev = hw->priv; - u8 nstreams = dev->mt76.chainmask & 0xf; - - *dbm = dev->mt76.txpower_cur / 2; - - /* convert from per-chain power to combined - * output on 2x2 devices - */ - if (nstreams > 1) - *dbm += 3; - - return 0; -} -EXPORT_SYMBOL_GPL(mt76x02_get_txpower); - void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 6a87b88eb036..06a26a152ba4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -191,7 +191,7 @@ const struct ieee80211_ops mt76x2_ops = { .sw_scan_complete = mt76x02_sw_scan_complete, .flush = mt76x2_flush, .ampdu_action = mt76x02_ampdu_action, - .get_txpower = mt76x02_get_txpower, + .get_txpower = mt76_get_txpower, .wake_tx_queue = mt76_wake_tx_queue, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .release_buffered_frames = mt76_release_buffered_frames, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 2b48cc51a30d..286c7f451090 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -138,5 +138,5 @@ const struct ieee80211_ops mt76x2u_ops = { .sw_scan_start = mt76x02_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, - .get_txpower = mt76x02_get_txpower, + .get_txpower = mt76_get_txpower, }; -- cgit v1.2.3 From ef13edc0070818f5cddb3a1d31957cc618e25e9d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 5 Dec 2018 17:06:58 +0100 Subject: mt76: move mt76x02_phy_get_min_avg_rssi to mt76 core This will be used by mt7603 as well Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 8 +++- drivers/net/wireless/mediatek/mt76/mt76.h | 8 ++++ drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 4 +- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 5 --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 6 --- drivers/net/wireless/mediatek/mt76/mt76x02_phy.c | 47 ----------------------- drivers/net/wireless/mediatek/mt76/mt76x02_phy.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 - drivers/net/wireless/mediatek/mt76/mt76x2/phy.c | 4 +- drivers/net/wireless/mediatek/mt76/util.c | 42 ++++++++++++++++++++ 10 files changed, 62 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 467b5a692ed1..226f98fff6ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -548,7 +548,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb) } static void -mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb) +mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -567,6 +567,9 @@ mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb) sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv); + ewma_signal_add(&wcid->rssi, status->signal); + wcid->inactive_count = 0; + if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) return; @@ -626,7 +629,7 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, __skb_queue_head_init(&frames); while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { - mt76_check_ps(dev, skb); + mt76_check_sta(dev, skb); mt76_rx_aggr_reorder(skb, &frames); } @@ -660,6 +663,7 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, mt76_txq_init(dev, sta->txq[i]); } + ewma_signal_init(&wcid->rssi); rcu_assign_pointer(dev->wcid[wcid->idx], wcid); out: diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 16b342f63d29..2267163d2445 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "util.h" @@ -174,6 +175,8 @@ enum mt76_wcid_flags { #define MT76_N_WCIDS 128 +DECLARE_EWMA(signal, 10, 8); + struct mt76_wcid { struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS]; @@ -181,6 +184,9 @@ struct mt76_wcid { unsigned long flags; + struct ewma_signal rssi; + int inactive_count; + u8 idx; u8 hw_key_idx; @@ -680,6 +686,8 @@ int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb); +int mt76_get_min_avg_rssi(struct mt76_dev *dev); + int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index b2b38b9fcac7..5a4c6f34267e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -1077,7 +1077,9 @@ mt76x0_phy_update_channel_gain(struct mt76x02_dev *dev) u8 gain_delta; int low_gain; - dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev); + dev->cal.avg_rssi_all = mt76_get_min_avg_rssi(&dev->mt76); + if (!dev->cal.avg_rssi_all) + dev->cal.avg_rssi_all = -75; low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) + (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 38cd77d30f5c..68d01e136fa0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -656,11 +656,6 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, status->tid = FIELD_GET(MT_RXWI_TID, tid_sn); status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn); - if (sta) { - ewma_signal_add(&sta->rssi, status->signal); - sta->inactive_count = 0; - } - return mt76x02_mac_process_rate(status, rate); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 735fe96440ba..940c07f665cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -18,8 +18,6 @@ #ifndef __MT76X02_MAC_H #define __MT76X02_MAC_H -#include - struct mt76x02_dev; struct mt76x02_tx_status { @@ -41,8 +39,6 @@ struct mt76x02_vif { u8 idx; }; -DECLARE_EWMA(signal, 10, 8); - struct mt76x02_sta { struct mt76_wcid wcid; /* must be first */ @@ -50,8 +46,6 @@ struct mt76x02_sta { struct mt76x02_tx_status status; int n_frames; - struct ewma_signal rssi; - int inactive_count; }; #define MT_RXINFO_BA BIT(0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index 977a8e7e26df..a020c757ba5c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -132,53 +132,6 @@ void mt76x02_phy_set_txpower(struct mt76x02_dev *dev, int txp_0, int txp_1) } EXPORT_SYMBOL_GPL(mt76x02_phy_set_txpower); -int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev) -{ - struct mt76x02_sta *sta; - struct mt76_wcid *wcid; - int i, j, min_rssi = 0; - s8 cur_rssi; - - local_bh_disable(); - rcu_read_lock(); - - for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid_mask); i++) { - unsigned long mask = dev->mt76.wcid_mask[i]; - - if (!mask) - continue; - - for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) { - if (!(mask & 1)) - continue; - - wcid = rcu_dereference(dev->mt76.wcid[j]); - if (!wcid) - continue; - - sta = container_of(wcid, struct mt76x02_sta, wcid); - spin_lock(&dev->mt76.rx_lock); - if (sta->inactive_count++ < 5) - cur_rssi = ewma_signal_read(&sta->rssi); - else - cur_rssi = 0; - spin_unlock(&dev->mt76.rx_lock); - - if (cur_rssi < min_rssi) - min_rssi = cur_rssi; - } - } - - rcu_read_unlock(); - local_bh_enable(); - - if (!min_rssi) - return -75; - - return min_rssi; -} -EXPORT_SYMBOL_GPL(mt76x02_phy_get_min_avg_rssi); - void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl) { int core_val, agc_val; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index 2b316cf7c70c..d2971db06f13 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -51,7 +51,6 @@ void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit); int mt76x02_get_max_rate_power(struct mt76_rate_power *r); void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev); void mt76x02_phy_set_txdac(struct mt76x02_dev *dev); -int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev); void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl); void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 59f50a957cd5..0bd23d64db24 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -250,8 +250,6 @@ int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); - ewma_signal_init(&msta->rssi); - return 0; } EXPORT_SYMBOL_GPL(mt76x02_sta_add); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index c9634a774705..e2ee5e498da7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -284,7 +284,9 @@ void mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) int low_gain; u32 val; - dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev); + dev->cal.avg_rssi_all = mt76_get_min_avg_rssi(&dev->mt76); + if (!dev->cal.avg_rssi_all) + dev->cal.avg_rssi_all = -75; low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) + (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c index 0c35b8db58cd..6242421c6011 100644 --- a/drivers/net/wireless/mediatek/mt76/util.c +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -75,4 +75,46 @@ int mt76_wcid_alloc(unsigned long *mask, int size) } EXPORT_SYMBOL_GPL(mt76_wcid_alloc); +int mt76_get_min_avg_rssi(struct mt76_dev *dev) +{ + struct mt76_wcid *wcid; + int i, j, min_rssi = 0; + s8 cur_rssi; + + local_bh_disable(); + rcu_read_lock(); + + for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { + unsigned long mask = dev->wcid_mask[i]; + + if (!mask) + continue; + + for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) { + if (!(mask & 1)) + continue; + + wcid = rcu_dereference(dev->wcid[j]); + if (!wcid) + continue; + + spin_lock(&dev->rx_lock); + if (wcid->inactive_count++ < 5) + cur_rssi = ewma_signal_read(&wcid->rssi); + else + cur_rssi = 0; + spin_unlock(&dev->rx_lock); + + if (cur_rssi < min_rssi) + min_rssi = cur_rssi; + } + } + + rcu_read_unlock(); + local_bh_enable(); + + return min_rssi; +} +EXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi); + MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 02e5a769c0a48e4e145b765329bc9d22a70261e7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 11 Jan 2019 14:17:30 +0100 Subject: mt76: fix rssi ewma tracking The generic EWMA code cannot deal with negative numbers, so convert signal to a positive number before adding it Fixes mt76x2 AGC tuning Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 +++- drivers/net/wireless/mediatek/mt76/util.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 226f98fff6ef..3b09d4560ae2 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -567,7 +567,9 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv); - ewma_signal_add(&wcid->rssi, status->signal); + if (status->signal <= 0) + ewma_signal_add(&wcid->rssi, -status->signal); + wcid->inactive_count = 0; if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c index 6242421c6011..69270c1a9091 100644 --- a/drivers/net/wireless/mediatek/mt76/util.c +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -100,7 +100,7 @@ int mt76_get_min_avg_rssi(struct mt76_dev *dev) spin_lock(&dev->rx_lock); if (wcid->inactive_count++ < 5) - cur_rssi = ewma_signal_read(&wcid->rssi); + cur_rssi = -ewma_signal_read(&wcid->rssi); else cur_rssi = 0; spin_unlock(&dev->rx_lock); -- cgit v1.2.3 From 9cf67ec7fd8077fdf7909449534e32b8438b5edc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 29 Dec 2018 13:01:31 +0100 Subject: mt76: fix signedness of rx status signal field It is usually negative, so it needs to be signed. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2267163d2445..0435d623e9ad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -497,7 +497,7 @@ struct mt76_rx_status { u8 rate_idx; u8 nss; u8 band; - u8 signal; + s8 signal; u8 chains; s8 chain_signal[IEEE80211_MAX_CHAINS]; }; -- cgit v1.2.3 From e7173858c78a981788bde18930d1e16fd5203151 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 15 Jan 2019 14:26:53 +0100 Subject: mt76: add channel switch announcement support Use the appropriate mac80211 callbacks after beacon transmission Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 39 +++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 5 +++ drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 13 ++++++-- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 ++ 4 files changed, 57 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 3b09d4560ae2..ee3b65a14870 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -734,3 +734,42 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } EXPORT_SYMBOL_GPL(mt76_get_txpower); + +static void +__mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + if (vif->csa_active && ieee80211_csa_is_complete(vif)) + ieee80211_csa_finish(vif); +} + +void mt76_csa_finish(struct mt76_dev *dev) +{ + if (!dev->csa_complete) + return; + + ieee80211_iterate_active_interfaces_atomic(dev->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + __mt76_csa_finish, dev); + + dev->csa_complete = 0; +} +EXPORT_SYMBOL_GPL(mt76_csa_finish); + +static void +__mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt76_dev *dev = priv; + + if (!vif->csa_active) + return; + + dev->csa_complete |= ieee80211_csa_is_complete(vif); +} + +void mt76_csa_check(struct mt76_dev *dev) +{ + ieee80211_iterate_active_interfaces_atomic(dev->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + __mt76_csa_check, dev); +} +EXPORT_SYMBOL_GPL(mt76_csa_check); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 0435d623e9ad..2bb9db4ed80a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -463,6 +463,8 @@ struct mt76_dev { bool led_al; u8 led_pin; + u8 csa_complete; + u32 rxfilter; union { @@ -691,6 +693,9 @@ int mt76_get_min_avg_rssi(struct mt76_dev *dev); int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm); +void mt76_csa_check(struct mt76_dev *dev); +void mt76_csa_finish(struct mt76_dev *dev); + /* internal */ void mt76_tx_free(struct mt76_dev *dev); struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 6236c6121c01..374bc9d91f12 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -116,6 +116,11 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg) IEEE80211_IFACE_ITER_RESUME_ALL, mt76x02_update_beacon_iter, dev); + mt76_csa_check(&dev->mt76); + + if (dev->mt76.csa_complete) + return; + do { nframes = skb_queue_len(&data.q); ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), @@ -309,8 +314,12 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance) tasklet_schedule(&dev->pre_tbtt_tasklet); /* send buffered multicast frames now */ - if (intr & MT_INT_TBTT) - mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]); + if (intr & MT_INT_TBTT) { + if (dev->mt76.csa_complete) + mt76_csa_finish(&dev->mt76); + else + mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]); + } if (intr & MT_INT_TX_STAT) { mt76x02_mac_poll_tx_status(dev, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 0bd23d64db24..062614ad0d51 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -160,6 +160,8 @@ void mt76x02_init_device(struct mt76x02_dev *dev) #endif BIT(NL80211_IFTYPE_ADHOC); + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); /* init led callbacks */ -- cgit v1.2.3 From e8f9b16d72631870e30a3d8e4ee9f1c097bc7ba0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 17 Jan 2019 07:53:55 -0500 Subject: media: remove soc_camera ov9640 This driver got converted to not depend on soc_camera on commit 57b0ad9ebe60 ("media: soc_camera: ov9640: move ov9640 out of soc_camera"). There's no sense on keeping the old version there. Acked-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/Kconfig | 8 - drivers/media/i2c/soc_camera/Makefile | 1 - drivers/media/i2c/soc_camera/ov9640.h | 208 --------- drivers/media/i2c/soc_camera/soc_ov9640.c | 738 ------------------------------ 4 files changed, 955 deletions(-) delete mode 100644 drivers/media/i2c/soc_camera/ov9640.h delete mode 100644 drivers/media/i2c/soc_camera/soc_ov9640.c (limited to 'drivers') diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 7d7b801ab2ce..f67499187bda 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -41,14 +41,6 @@ config SOC_CAMERA_OV772X help This is a ov772x camera driver -config SOC_CAMERA_OV9640 - tristate "ov9640 camera support (OBSOLETE)" - default n - depends on SOC_CAMERA && I2C - help - This is an obsoleted version of ov9640 camera driver. Please use - the v4l2 standalone one (VIDEO_OV9640). - config SOC_CAMERA_OV9740 tristate "ov9740 camera support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index 09ae483b96ef..0d15864cfda8 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_SOC_CAMERA_MT9T112) += soc_mt9t112.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += soc_mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV5642) += soc_ov5642.o obj-$(CONFIG_SOC_CAMERA_OV772X) += soc_ov772x.o -obj-$(CONFIG_SOC_CAMERA_OV9640) += soc_ov9640.o obj-$(CONFIG_SOC_CAMERA_OV9740) += soc_ov9740.o obj-$(CONFIG_SOC_CAMERA_RJ54N1) += soc_rj54n1cb0c.o obj-$(CONFIG_SOC_CAMERA_TW9910) += soc_tw9910.o diff --git a/drivers/media/i2c/soc_camera/ov9640.h b/drivers/media/i2c/soc_camera/ov9640.h deleted file mode 100644 index 65d13ff17536..000000000000 --- a/drivers/media/i2c/soc_camera/ov9640.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * OmniVision OV96xx Camera Header File - * - * Copyright (C) 2009 Marek Vasut - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __DRIVERS_MEDIA_VIDEO_OV9640_H__ -#define __DRIVERS_MEDIA_VIDEO_OV9640_H__ - -/* Register definitions */ -#define OV9640_GAIN 0x00 -#define OV9640_BLUE 0x01 -#define OV9640_RED 0x02 -#define OV9640_VFER 0x03 -#define OV9640_COM1 0x04 -#define OV9640_BAVE 0x05 -#define OV9640_GEAVE 0x06 -#define OV9640_RSID 0x07 -#define OV9640_RAVE 0x08 -#define OV9640_COM2 0x09 -#define OV9640_PID 0x0a -#define OV9640_VER 0x0b -#define OV9640_COM3 0x0c -#define OV9640_COM4 0x0d -#define OV9640_COM5 0x0e -#define OV9640_COM6 0x0f -#define OV9640_AECH 0x10 -#define OV9640_CLKRC 0x11 -#define OV9640_COM7 0x12 -#define OV9640_COM8 0x13 -#define OV9640_COM9 0x14 -#define OV9640_COM10 0x15 -/* 0x16 - RESERVED */ -#define OV9640_HSTART 0x17 -#define OV9640_HSTOP 0x18 -#define OV9640_VSTART 0x19 -#define OV9640_VSTOP 0x1a -#define OV9640_PSHFT 0x1b -#define OV9640_MIDH 0x1c -#define OV9640_MIDL 0x1d -#define OV9640_MVFP 0x1e -#define OV9640_LAEC 0x1f -#define OV9640_BOS 0x20 -#define OV9640_GBOS 0x21 -#define OV9640_GROS 0x22 -#define OV9640_ROS 0x23 -#define OV9640_AEW 0x24 -#define OV9640_AEB 0x25 -#define OV9640_VPT 0x26 -#define OV9640_BBIAS 0x27 -#define OV9640_GBBIAS 0x28 -/* 0x29 - RESERVED */ -#define OV9640_EXHCH 0x2a -#define OV9640_EXHCL 0x2b -#define OV9640_RBIAS 0x2c -#define OV9640_ADVFL 0x2d -#define OV9640_ADVFH 0x2e -#define OV9640_YAVE 0x2f -#define OV9640_HSYST 0x30 -#define OV9640_HSYEN 0x31 -#define OV9640_HREF 0x32 -#define OV9640_CHLF 0x33 -#define OV9640_ARBLM 0x34 -/* 0x35..0x36 - RESERVED */ -#define OV9640_ADC 0x37 -#define OV9640_ACOM 0x38 -#define OV9640_OFON 0x39 -#define OV9640_TSLB 0x3a -#define OV9640_COM11 0x3b -#define OV9640_COM12 0x3c -#define OV9640_COM13 0x3d -#define OV9640_COM14 0x3e -#define OV9640_EDGE 0x3f -#define OV9640_COM15 0x40 -#define OV9640_COM16 0x41 -#define OV9640_COM17 0x42 -/* 0x43..0x4e - RESERVED */ -#define OV9640_MTX1 0x4f -#define OV9640_MTX2 0x50 -#define OV9640_MTX3 0x51 -#define OV9640_MTX4 0x52 -#define OV9640_MTX5 0x53 -#define OV9640_MTX6 0x54 -#define OV9640_MTX7 0x55 -#define OV9640_MTX8 0x56 -#define OV9640_MTX9 0x57 -#define OV9640_MTXS 0x58 -/* 0x59..0x61 - RESERVED */ -#define OV9640_LCC1 0x62 -#define OV9640_LCC2 0x63 -#define OV9640_LCC3 0x64 -#define OV9640_LCC4 0x65 -#define OV9640_LCC5 0x66 -#define OV9640_MANU 0x67 -#define OV9640_MANV 0x68 -#define OV9640_HV 0x69 -#define OV9640_MBD 0x6a -#define OV9640_DBLV 0x6b -#define OV9640_GSP 0x6c /* ... till 0x7b */ -#define OV9640_GST 0x7c /* ... till 0x8a */ - -#define OV9640_CLKRC_DPLL_EN 0x80 -#define OV9640_CLKRC_DIRECT 0x40 -#define OV9640_CLKRC_DIV(x) ((x) & 0x3f) - -#define OV9640_PSHFT_VAL(x) ((x) & 0xff) - -#define OV9640_ACOM_2X_ANALOG 0x80 -#define OV9640_ACOM_RSVD 0x12 - -#define OV9640_MVFP_V 0x10 -#define OV9640_MVFP_H 0x20 - -#define OV9640_COM1_HREF_NOSKIP 0x00 -#define OV9640_COM1_HREF_2SKIP 0x04 -#define OV9640_COM1_HREF_3SKIP 0x08 -#define OV9640_COM1_QQFMT 0x20 - -#define OV9640_COM2_SSM 0x10 - -#define OV9640_COM3_VP 0x04 - -#define OV9640_COM4_QQ_VP 0x80 -#define OV9640_COM4_RSVD 0x40 - -#define OV9640_COM5_SYSCLK 0x80 -#define OV9640_COM5_LONGEXP 0x01 - -#define OV9640_COM6_OPT_BLC 0x40 -#define OV9640_COM6_ADBLC_BIAS 0x08 -#define OV9640_COM6_FMT_RST 0x82 -#define OV9640_COM6_ADBLC_OPTEN 0x01 - -#define OV9640_COM7_RAW_RGB 0x01 -#define OV9640_COM7_RGB 0x04 -#define OV9640_COM7_QCIF 0x08 -#define OV9640_COM7_QVGA 0x10 -#define OV9640_COM7_CIF 0x20 -#define OV9640_COM7_VGA 0x40 -#define OV9640_COM7_SCCB_RESET 0x80 - -#define OV9640_TSLB_YVYU_YUYV 0x04 -#define OV9640_TSLB_YUYV_UYVY 0x08 - -#define OV9640_COM12_YUV_AVG 0x04 -#define OV9640_COM12_RSVD 0x40 - -#define OV9640_COM13_GAMMA_NONE 0x00 -#define OV9640_COM13_GAMMA_Y 0x40 -#define OV9640_COM13_GAMMA_RAW 0x80 -#define OV9640_COM13_RGB_AVG 0x20 -#define OV9640_COM13_MATRIX_EN 0x10 -#define OV9640_COM13_Y_DELAY_EN 0x08 -#define OV9640_COM13_YUV_DLY(x) ((x) & 0x07) - -#define OV9640_COM15_OR_00FF 0x00 -#define OV9640_COM15_OR_01FE 0x40 -#define OV9640_COM15_OR_10F0 0xc0 -#define OV9640_COM15_RGB_NORM 0x00 -#define OV9640_COM15_RGB_565 0x10 -#define OV9640_COM15_RGB_555 0x30 - -#define OV9640_COM16_RB_AVG 0x01 - -/* IDs */ -#define OV9640_V2 0x9648 -#define OV9640_V3 0x9649 -#define VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xFF)) - -/* supported resolutions */ -enum { - W_QQCIF = 88, - W_QQVGA = 160, - W_QCIF = 176, - W_QVGA = 320, - W_CIF = 352, - W_VGA = 640, - W_SXGA = 1280 -}; -#define H_SXGA 960 - -/* Misc. structures */ -struct ov9640_reg_alt { - u8 com7; - u8 com12; - u8 com13; - u8 com15; -}; - -struct ov9640_reg { - u8 reg; - u8 val; -}; - -struct ov9640_priv { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct v4l2_clk *clk; - - int model; - int revision; -}; - -#endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ diff --git a/drivers/media/i2c/soc_camera/soc_ov9640.c b/drivers/media/i2c/soc_camera/soc_ov9640.c deleted file mode 100644 index eb91b8240083..000000000000 --- a/drivers/media/i2c/soc_camera/soc_ov9640.c +++ /dev/null @@ -1,738 +0,0 @@ -/* - * OmniVision OV96xx Camera Driver - * - * Copyright (C) 2009 Marek Vasut - * - * Based on ov772x camera driver: - * - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto - * - * Based on ov7670 and soc_camera_platform driver, - * - * Copyright 2006-7 Jonathan Corbet - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "ov9640.h" - -#define to_ov9640_sensor(sd) container_of(sd, struct ov9640_priv, subdev) - -/* default register setup */ -static const struct ov9640_reg ov9640_regs_dflt[] = { - { OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP }, - { OV9640_COM6, OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS | - OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN }, - { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) }, - { OV9640_ACOM, OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD }, - { OV9640_TSLB, OV9640_TSLB_YUYV_UYVY }, - { OV9640_COM16, OV9640_COM16_RB_AVG }, - - /* Gamma curve P */ - { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 }, - { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 }, - { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, - { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 }, - - /* Gamma curve T */ - { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 }, - { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, - { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e }, - { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 }, -}; - -/* Configurations - * NOTE: for YUV, alter the following registers: - * COM12 |= OV9640_COM12_YUV_AVG - * - * for RGB, alter the following registers: - * COM7 |= OV9640_COM7_RGB - * COM13 |= OV9640_COM13_RGB_AVG - * COM15 |= proper RGB color encoding mode - */ -static const struct ov9640_reg ov9640_regs_qqcif[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) }, - { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP }, - { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, - { OV9640_COM7, OV9640_COM7_QCIF }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_qqvga[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) }, - { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP }, - { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, - { OV9640_COM7, OV9640_COM7_QVGA }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_qcif[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) }, - { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, - { OV9640_COM7, OV9640_COM7_QCIF }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_qvga[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) }, - { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, - { OV9640_COM7, OV9640_COM7_QVGA }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_cif[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) }, - { OV9640_COM3, OV9640_COM3_VP }, - { OV9640_COM7, OV9640_COM7_CIF }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_vga[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) }, - { OV9640_COM3, OV9640_COM3_VP }, - { OV9640_COM7, OV9640_COM7_VGA }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_sxga[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) }, - { OV9640_COM3, OV9640_COM3_VP }, - { OV9640_COM7, 0 }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_yuv[] = { - { OV9640_MTX1, 0x58 }, - { OV9640_MTX2, 0x48 }, - { OV9640_MTX3, 0x10 }, - { OV9640_MTX4, 0x28 }, - { OV9640_MTX5, 0x48 }, - { OV9640_MTX6, 0x70 }, - { OV9640_MTX7, 0x40 }, - { OV9640_MTX8, 0x40 }, - { OV9640_MTX9, 0x40 }, - { OV9640_MTXS, 0x0f }, -}; - -static const struct ov9640_reg ov9640_regs_rgb[] = { - { OV9640_MTX1, 0x71 }, - { OV9640_MTX2, 0x3e }, - { OV9640_MTX3, 0x0c }, - { OV9640_MTX4, 0x33 }, - { OV9640_MTX5, 0x72 }, - { OV9640_MTX6, 0x00 }, - { OV9640_MTX7, 0x2b }, - { OV9640_MTX8, 0x66 }, - { OV9640_MTX9, 0xd2 }, - { OV9640_MTXS, 0x65 }, -}; - -static u32 ov9640_codes[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - MEDIA_BUS_FMT_RGB565_2X8_LE, -}; - -/* read a register */ -static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) -{ - int ret; - u8 data = reg; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - msg.flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - *val = data; - return 0; - -err: - dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg); - return ret; -} - -/* write a register */ -static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val) -{ - int ret; - u8 _val; - unsigned char data[2] = { reg, val }; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); - return ret; - } - - /* we have to read the register back ... no idea why, maybe HW bug */ - ret = ov9640_reg_read(client, reg, &_val); - if (ret) - dev_err(&client->dev, - "Failed reading back register 0x%02x!\n", reg); - - return 0; -} - - -/* Read a register, alter its bits, write it back */ -static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset) -{ - u8 val; - int ret; - - ret = ov9640_reg_read(client, reg, &val); - if (ret) { - dev_err(&client->dev, - "[Read]-Modify-Write of register %02x failed!\n", reg); - return ret; - } - - val |= set; - val &= ~unset; - - ret = ov9640_reg_write(client, reg, val); - if (ret) - dev_err(&client->dev, - "Read-Modify-[Write] of register %02x failed!\n", reg); - - return ret; -} - -/* Soft reset the camera. This has nothing to do with the RESET pin! */ -static int ov9640_reset(struct i2c_client *client) -{ - int ret; - - ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET); - if (ret) - dev_err(&client->dev, - "An error occurred while entering soft reset!\n"); - - return ret; -} - -/* Start/Stop streaming from the device */ -static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) -{ - return 0; -} - -/* Set status of additional camera capabilities */ -static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); - struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->val) - return ov9640_reg_rmw(client, OV9640_MVFP, - OV9640_MVFP_V, 0); - return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); - case V4L2_CID_HFLIP: - if (ctrl->val) - return ov9640_reg_rmw(client, OV9640_MVFP, - OV9640_MVFP_H, 0); - return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); - } - return -EINVAL; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov9640_get_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 val; - - if (reg->reg & ~0xff) - return -EINVAL; - - reg->size = 1; - - ret = ov9640_reg_read(client, reg->reg, &val); - if (ret) - return ret; - - reg->val = (__u64)val; - - return 0; -} - -static int ov9640_set_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg & ~0xff || reg->val & ~0xff) - return -EINVAL; - - return ov9640_reg_write(client, reg->reg, reg->val); -} -#endif - -static int ov9640_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); -} - -/* select nearest higher resolution for capture */ -static void ov9640_res_roundup(u32 *width, u32 *height) -{ - int i; - enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA }; - static const int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; - static const int res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; - - for (i = 0; i < ARRAY_SIZE(res_x); i++) { - if (res_x[i] >= *width && res_y[i] >= *height) { - *width = res_x[i]; - *height = res_y[i]; - return; - } - } - - *width = res_x[SXGA]; - *height = res_y[SXGA]; -} - -/* Prepare necessary register changes depending on color encoding */ -static void ov9640_alter_regs(u32 code, - struct ov9640_reg_alt *alt) -{ - switch (code) { - default: - case MEDIA_BUS_FMT_UYVY8_2X8: - alt->com12 = OV9640_COM12_YUV_AVG; - alt->com13 = OV9640_COM13_Y_DELAY_EN | - OV9640_COM13_YUV_DLY(0x01); - break; - case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: - alt->com7 = OV9640_COM7_RGB; - alt->com13 = OV9640_COM13_RGB_AVG; - alt->com15 = OV9640_COM15_RGB_555; - break; - case MEDIA_BUS_FMT_RGB565_2X8_LE: - alt->com7 = OV9640_COM7_RGB; - alt->com13 = OV9640_COM13_RGB_AVG; - alt->com15 = OV9640_COM15_RGB_565; - break; - } -} - -/* Setup registers according to resolution and color encoding */ -static int ov9640_write_regs(struct i2c_client *client, u32 width, - u32 code, struct ov9640_reg_alt *alts) -{ - const struct ov9640_reg *ov9640_regs, *matrix_regs; - int ov9640_regs_len, matrix_regs_len; - int i, ret; - u8 val; - - /* select register configuration for given resolution */ - switch (width) { - case W_QQCIF: - ov9640_regs = ov9640_regs_qqcif; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif); - break; - case W_QQVGA: - ov9640_regs = ov9640_regs_qqvga; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga); - break; - case W_QCIF: - ov9640_regs = ov9640_regs_qcif; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif); - break; - case W_QVGA: - ov9640_regs = ov9640_regs_qvga; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga); - break; - case W_CIF: - ov9640_regs = ov9640_regs_cif; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif); - break; - case W_VGA: - ov9640_regs = ov9640_regs_vga; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga); - break; - case W_SXGA: - ov9640_regs = ov9640_regs_sxga; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga); - break; - default: - dev_err(&client->dev, "Failed to select resolution!\n"); - return -EINVAL; - } - - /* select color matrix configuration for given color encoding */ - if (code == MEDIA_BUS_FMT_UYVY8_2X8) { - matrix_regs = ov9640_regs_yuv; - matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv); - } else { - matrix_regs = ov9640_regs_rgb; - matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb); - } - - /* write register settings into the module */ - for (i = 0; i < ov9640_regs_len; i++) { - val = ov9640_regs[i].val; - - switch (ov9640_regs[i].reg) { - case OV9640_COM7: - val |= alts->com7; - break; - case OV9640_COM12: - val |= alts->com12; - break; - case OV9640_COM13: - val |= alts->com13; - break; - case OV9640_COM15: - val |= alts->com15; - break; - } - - ret = ov9640_reg_write(client, ov9640_regs[i].reg, val); - if (ret) - return ret; - } - - /* write color matrix configuration into the module */ - for (i = 0; i < matrix_regs_len; i++) { - ret = ov9640_reg_write(client, matrix_regs[i].reg, - matrix_regs[i].val); - if (ret) - return ret; - } - - return 0; -} - -/* program default register values */ -static int ov9640_prog_dflt(struct i2c_client *client) -{ - int i, ret; - - for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) { - ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg, - ov9640_regs_dflt[i].val); - if (ret) - return ret; - } - - /* wait for the changes to actually happen, 140ms are not enough yet */ - mdelay(150); - - return 0; -} - -/* set the format we will capture in */ -static int ov9640_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov9640_reg_alt alts = {0}; - int ret; - - ov9640_alter_regs(mf->code, &alts); - - ov9640_reset(client); - - ret = ov9640_prog_dflt(client); - if (ret) - return ret; - - return ov9640_write_regs(client, mf->width, mf->code, &alts); -} - -static int ov9640_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - - if (format->pad) - return -EINVAL; - - ov9640_res_roundup(&mf->width, &mf->height); - - mf->field = V4L2_FIELD_NONE; - - switch (mf->code) { - case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - default: - mf->code = MEDIA_BUS_FMT_UYVY8_2X8; - /* fall through */ - case MEDIA_BUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - break; - } - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return ov9640_s_fmt(sd, mf); - - cfg->try_fmt = *mf; - return 0; -} - -static int ov9640_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes)) - return -EINVAL; - - code->code = ov9640_codes[code->index]; - return 0; -} - -static int ov9640_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - sel->r.left = 0; - sel->r.top = 0; - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP: - sel->r.width = W_SXGA; - sel->r.height = H_SXGA; - return 0; - default: - return -EINVAL; - } -} - -static int ov9640_video_probe(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9640_priv *priv = to_ov9640_sensor(sd); - u8 pid, ver, midh, midl; - const char *devname; - int ret; - - ret = ov9640_s_power(&priv->subdev, 1); - if (ret < 0) - return ret; - - /* - * check and show product ID and manufacturer ID - */ - - ret = ov9640_reg_read(client, OV9640_PID, &pid); - if (!ret) - ret = ov9640_reg_read(client, OV9640_VER, &ver); - if (!ret) - ret = ov9640_reg_read(client, OV9640_MIDH, &midh); - if (!ret) - ret = ov9640_reg_read(client, OV9640_MIDL, &midl); - if (ret) - goto done; - - switch (VERSION(pid, ver)) { - case OV9640_V2: - devname = "ov9640"; - priv->revision = 2; - break; - case OV9640_V3: - devname = "ov9640"; - priv->revision = 3; - break; - default: - dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", - devname, pid, ver, midh, midl); - - ret = v4l2_ctrl_handler_setup(&priv->hdl); - -done: - ov9640_s_power(&priv->subdev, 0); - return ret; -} - -static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { - .s_ctrl = ov9640_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops ov9640_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov9640_get_register, - .s_register = ov9640_set_register, -#endif - .s_power = ov9640_s_power, -}; - -/* Request bus settings on camera side */ -static int ov9640_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static const struct v4l2_subdev_video_ops ov9640_video_ops = { - .s_stream = ov9640_s_stream, - .g_mbus_config = ov9640_g_mbus_config, -}; - -static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { - .enum_mbus_code = ov9640_enum_mbus_code, - .get_selection = ov9640_get_selection, - .set_fmt = ov9640_set_fmt, -}; - -static const struct v4l2_subdev_ops ov9640_subdev_ops = { - .core = &ov9640_core_ops, - .video = &ov9640_video_ops, - .pad = &ov9640_pad_ops, -}; - -/* - * i2c_driver function - */ -static int ov9640_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov9640_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - int ret; - - if (!ssdd) { - dev_err(&client->dev, "Missing platform_data for driver\n"); - return -EINVAL; - } - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); - - v4l2_ctrl_handler_init(&priv->hdl, 2); - v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) - return priv->hdl.error; - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - goto eclkget; - } - - ret = ov9640_video_probe(client); - if (ret) { - v4l2_clk_put(priv->clk); -eclkget: - v4l2_ctrl_handler_free(&priv->hdl); - } - - return ret; -} - -static int ov9640_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - v4l2_clk_put(priv->clk); - v4l2_device_unregister_subdev(&priv->subdev); - v4l2_ctrl_handler_free(&priv->hdl); - return 0; -} - -static const struct i2c_device_id ov9640_id[] = { - { "ov9640", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov9640_id); - -static struct i2c_driver ov9640_i2c_driver = { - .driver = { - .name = "ov9640", - }, - .probe = ov9640_probe, - .remove = ov9640_remove, - .id_table = ov9640_id, -}; - -module_i2c_driver(ov9640_i2c_driver); - -MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); -MODULE_AUTHOR("Marek Vasut "); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 5b8e432dbb0e20bd8e99033f4a0bfa0d38c0e08e Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Tue, 15 Jan 2019 00:41:43 +0800 Subject: xen/blkback: add stack variable 'blkif' in connect_ring() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As 'be->blkif' is used for many times in connect_ring(), the stack variable 'blkif' is added to substitute 'be-blkif'. Suggested-by: Paul Durrant Signed-off-by: Dongli Zhang Reviewed-by: Paul Durrant Reviewed-by: Roger Pau Monné Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/xenbus.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index a4bc74e72c39..a4aadac772e5 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -1023,6 +1023,7 @@ fail: static int connect_ring(struct backend_info *be) { struct xenbus_device *dev = be->dev; + struct xen_blkif *blkif = be->blkif; unsigned int pers_grants; char protocol[64] = ""; int err, i; @@ -1033,25 +1034,25 @@ static int connect_ring(struct backend_info *be) pr_debug("%s %s\n", __func__, dev->otherend); - be->blkif->blk_protocol = BLKIF_PROTOCOL_DEFAULT; + blkif->blk_protocol = BLKIF_PROTOCOL_DEFAULT; err = xenbus_scanf(XBT_NIL, dev->otherend, "protocol", "%63s", protocol); if (err <= 0) strcpy(protocol, "unspecified, assuming default"); else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) - be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; + blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) - be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; + blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) - be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; + blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; else { xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol); return -ENOSYS; } pers_grants = xenbus_read_unsigned(dev->otherend, "feature-persistent", 0); - be->blkif->vbd.feature_gnt_persistent = pers_grants; - be->blkif->vbd.overflow_max_grants = 0; + blkif->vbd.feature_gnt_persistent = pers_grants; + blkif->vbd.overflow_max_grants = 0; /* * Read the number of hardware queues from frontend. @@ -1067,16 +1068,16 @@ static int connect_ring(struct backend_info *be) requested_num_queues, xenblk_max_queues); return -ENOSYS; } - be->blkif->nr_rings = requested_num_queues; - if (xen_blkif_alloc_rings(be->blkif)) + blkif->nr_rings = requested_num_queues; + if (xen_blkif_alloc_rings(blkif)) return -ENOMEM; pr_info("%s: using %d queues, protocol %d (%s) %s\n", dev->nodename, - be->blkif->nr_rings, be->blkif->blk_protocol, protocol, + blkif->nr_rings, blkif->blk_protocol, protocol, pers_grants ? "persistent grants" : ""); - if (be->blkif->nr_rings == 1) - return read_per_ring_refs(&be->blkif->rings[0], dev->otherend); + if (blkif->nr_rings == 1) + return read_per_ring_refs(&blkif->rings[0], dev->otherend); else { xspathsize = strlen(dev->otherend) + xenstore_path_ext_size; xspath = kmalloc(xspathsize, GFP_KERNEL); @@ -1085,10 +1086,10 @@ static int connect_ring(struct backend_info *be) return -ENOMEM; } - for (i = 0; i < be->blkif->nr_rings; i++) { + for (i = 0; i < blkif->nr_rings; i++) { memset(xspath, 0, xspathsize); snprintf(xspath, xspathsize, "%s/queue-%u", dev->otherend, i); - err = read_per_ring_refs(&be->blkif->rings[i], xspath); + err = read_per_ring_refs(&blkif->rings[i], xspath); if (err) { kfree(xspath); return err; -- cgit v1.2.3 From fd4b77e8deea9cced6c1eca8bd64d2f03fc7cc94 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 15 Jan 2019 09:53:22 +0100 Subject: drm/etnaviv: don't restrict to certain architectures The Vivante GPU cores are found in many different SoCs and the driver does not depend on anything architecture specific, so just drop the architecture restriction. Signed-off-by: Lucas Stach Acked-by: Sam Ravnborg --- drivers/gpu/drm/etnaviv/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig index 342591a1084e..21df44b78df3 100644 --- a/drivers/gpu/drm/etnaviv/Kconfig +++ b/drivers/gpu/drm/etnaviv/Kconfig @@ -2,7 +2,6 @@ config DRM_ETNAVIV tristate "ETNAVIV (DRM support for Vivante GPU IP cores)" depends on DRM - depends on ARCH_MXC || ARCH_DOVE || ARM || COMPILE_TEST depends on MMU select SHMEM select SYNC_FILE -- cgit v1.2.3 From 905b464ad9008905db099f90ae20f373c7051804 Mon Sep 17 00:00:00 2001 From: Xue Chaojing Date: Tue, 15 Jan 2019 17:48:52 +0000 Subject: net-next/hinic: replace disable_irq_nosync/enable_irq In order to avoid frequent system interrupts when sending and receiving packets. we replace disable_irq_nosync/enable_irq with hinic_set_msix_state(), hinic_set_msix_state is used to access memory mapped hinic devices. Signed-off-by: Xue Chaojing Signed-off-by: David S. Miller --- drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c | 13 +++++++++++ drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h | 3 +++ drivers/net/ethernet/huawei/hinic/hinic_hw_if.c | 28 ++++++++++++++++++++++++ drivers/net/ethernet/huawei/hinic/hinic_hw_if.h | 14 ++++++++++++ drivers/net/ethernet/huawei/hinic/hinic_rx.c | 11 ++++++++-- drivers/net/ethernet/huawei/hinic/hinic_tx.c | 8 +++++-- 6 files changed, 73 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c index 6b19607a4caa..3875f39f43bb 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c @@ -1008,3 +1008,16 @@ int hinic_hwdev_hw_ci_addr_set(struct hinic_hwdev *hwdev, struct hinic_sq *sq, &hw_ci, sizeof(hw_ci), NULL, NULL, HINIC_MGMT_MSG_SYNC); } + +/** + * hinic_hwdev_set_msix_state- set msix state + * @hwdev: the NIC HW device + * @msix_index: IRQ corresponding index number + * @flag: msix state + * + **/ +void hinic_hwdev_set_msix_state(struct hinic_hwdev *hwdev, u16 msix_index, + enum hinic_msix_state flag) +{ + hinic_set_msix_state(hwdev->hwif, msix_index, flag); +} diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h index d1a7d2522d82..c9e621e19dd0 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h @@ -240,4 +240,7 @@ int hinic_hwdev_msix_set(struct hinic_hwdev *hwdev, u16 msix_index, int hinic_hwdev_hw_ci_addr_set(struct hinic_hwdev *hwdev, struct hinic_sq *sq, u8 pending_limit, u8 coalesc_timer); +void hinic_hwdev_set_msix_state(struct hinic_hwdev *hwdev, u16 msix_index, + enum hinic_msix_state flag); + #endif diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c index 823a17061a97..9b160f076904 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c @@ -168,6 +168,22 @@ void hinic_db_state_set(struct hinic_hwif *hwif, hinic_hwif_write_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR, attr4); } +void hinic_set_msix_state(struct hinic_hwif *hwif, u16 msix_idx, + enum hinic_msix_state flag) +{ + u32 offset = msix_idx * HINIC_PCI_MSIX_ENTRY_SIZE + + HINIC_PCI_MSIX_ENTRY_VECTOR_CTRL; + u32 mask_bits; + + mask_bits = readl(hwif->intr_regs_base + offset); + mask_bits &= ~HINIC_PCI_MSIX_ENTRY_CTRL_MASKBIT; + + if (flag) + mask_bits |= HINIC_PCI_MSIX_ENTRY_CTRL_MASKBIT; + + writel(mask_bits, hwif->intr_regs_base + offset); +} + /** * hwif_ready - test if the HW is ready for use * @hwif: the HW interface of a pci function device @@ -321,6 +337,13 @@ int hinic_init_hwif(struct hinic_hwif *hwif, struct pci_dev *pdev) return -ENOMEM; } + hwif->intr_regs_base = pci_ioremap_bar(pdev, HINIC_PCI_INTR_REGS_BAR); + if (!hwif->intr_regs_base) { + dev_err(&pdev->dev, "Failed to map configuration regs\n"); + err = -ENOMEM; + goto err_map_intr_bar; + } + err = hwif_ready(hwif); if (err) { dev_err(&pdev->dev, "HW interface is not ready\n"); @@ -337,7 +360,11 @@ int hinic_init_hwif(struct hinic_hwif *hwif, struct pci_dev *pdev) return 0; err_hwif_ready: + iounmap(hwif->intr_regs_base); + +err_map_intr_bar: iounmap(hwif->cfg_regs_bar); + return err; } @@ -347,5 +374,6 @@ err_hwif_ready: **/ void hinic_free_hwif(struct hinic_hwif *hwif) { + iounmap(hwif->intr_regs_base); iounmap(hwif->cfg_regs_bar); } diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h index 5b4760c0e9f5..22ec7f73e0a6 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h @@ -152,6 +152,7 @@ #define HINIC_IS_PPF(hwif) (HINIC_FUNC_TYPE(hwif) == HINIC_PPF) #define HINIC_PCI_CFG_REGS_BAR 0 +#define HINIC_PCI_INTR_REGS_BAR 2 #define HINIC_PCI_DB_BAR 4 #define HINIC_PCIE_ST_DISABLE 0 @@ -164,6 +165,10 @@ #define HINIC_EQ_MSIX_LLI_CREDIT_LIMIT_DEFAULT 0 /* Disabled */ #define HINIC_EQ_MSIX_RESEND_TIMER_DEFAULT 7 /* max */ +#define HINIC_PCI_MSIX_ENTRY_SIZE 16 +#define HINIC_PCI_MSIX_ENTRY_VECTOR_CTRL 12 +#define HINIC_PCI_MSIX_ENTRY_CTRL_MASKBIT 1 + enum hinic_pcie_nosnoop { HINIC_PCIE_SNOOP = 0, HINIC_PCIE_NO_SNOOP = 1, @@ -207,6 +212,11 @@ enum hinic_db_state { HINIC_DB_DISABLE = 1, }; +enum hinic_msix_state { + HINIC_MSIX_ENABLE, + HINIC_MSIX_DISABLE, +}; + struct hinic_func_attr { u16 func_idx; u8 pf_idx; @@ -226,6 +236,7 @@ struct hinic_func_attr { struct hinic_hwif { struct pci_dev *pdev; void __iomem *cfg_regs_bar; + void __iomem *intr_regs_base; struct hinic_func_attr attr; }; @@ -251,6 +262,9 @@ int hinic_msix_attr_get(struct hinic_hwif *hwif, u16 msix_index, u8 *lli_timer, u8 *lli_credit_limit, u8 *resend_timer); +void hinic_set_msix_state(struct hinic_hwif *hwif, u16 msix_idx, + enum hinic_msix_state flag); + int hinic_msix_attr_cnt_clear(struct hinic_hwif *hwif, u16 msix_index); void hinic_set_pf_action(struct hinic_hwif *hwif, enum hinic_pf_action action); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c b/drivers/net/ethernet/huawei/hinic/hinic_rx.c index 0098b206e7e9..b6d218768ec1 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c @@ -381,6 +381,7 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget) static int rx_poll(struct napi_struct *napi, int budget) { struct hinic_rxq *rxq = container_of(napi, struct hinic_rxq, napi); + struct hinic_dev *nic_dev = netdev_priv(rxq->netdev); struct hinic_rq *rq = rxq->rq; int pkts; @@ -389,7 +390,10 @@ static int rx_poll(struct napi_struct *napi, int budget) return budget; napi_complete(napi); - enable_irq(rq->irq); + hinic_hwdev_set_msix_state(nic_dev->hwdev, + rq->msix_entry, + HINIC_MSIX_ENABLE); + return pkts; } @@ -414,7 +418,10 @@ static irqreturn_t rx_irq(int irq, void *data) struct hinic_dev *nic_dev; /* Disable the interrupt until napi will be completed */ - disable_irq_nosync(rq->irq); + nic_dev = netdev_priv(rxq->netdev); + hinic_hwdev_set_msix_state(nic_dev->hwdev, + rq->msix_entry, + HINIC_MSIX_DISABLE); nic_dev = netdev_priv(rxq->netdev); hinic_hwdev_msix_cnt_set(nic_dev->hwdev, rq->msix_entry); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c index 11e73e67358d..e17bf33eba0c 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c @@ -655,7 +655,9 @@ static int free_tx_poll(struct napi_struct *napi, int budget) if (pkts < budget) { napi_complete(napi); - enable_irq(sq->irq); + hinic_hwdev_set_msix_state(nic_dev->hwdev, + sq->msix_entry, + HINIC_MSIX_ENABLE); return pkts; } @@ -682,7 +684,9 @@ static irqreturn_t tx_irq(int irq, void *data) nic_dev = netdev_priv(txq->netdev); /* Disable the interrupt until napi will be completed */ - disable_irq_nosync(txq->sq->irq); + hinic_hwdev_set_msix_state(nic_dev->hwdev, + txq->sq->msix_entry, + HINIC_MSIX_DISABLE); hinic_hwdev_msix_cnt_set(nic_dev->hwdev, txq->sq->msix_entry); -- cgit v1.2.3 From 5db5ea995fc2fa89fdef61ef3a658cbb41a24222 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 15 Jan 2019 15:09:35 -0800 Subject: net: phy: Add helpers to determine if PHY driver is generic We are already checking in phy_detach() that the PHY driver is of generic kind (1G or 10G) and we are going to make use of that in the SFP layer as well for 1000BaseT SFP modules, so expose helper functions to return that information. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index bb1410821ce4..c02669270c41 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1277,6 +1277,36 @@ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, } EXPORT_SYMBOL(phy_attach); +static bool phy_driver_is_genphy_kind(struct phy_device *phydev, + struct device_driver *driver) +{ + struct device *d = &phydev->mdio.dev; + bool ret = false; + + if (!phydev->drv) + return ret; + + get_device(d); + ret = d->driver == driver; + put_device(d); + + return ret; +} + +bool phy_driver_is_genphy(struct phy_device *phydev) +{ + return phy_driver_is_genphy_kind(phydev, + &genphy_driver.mdiodrv.driver); +} +EXPORT_SYMBOL_GPL(phy_driver_is_genphy); + +bool phy_driver_is_genphy_10g(struct phy_device *phydev) +{ + return phy_driver_is_genphy_kind(phydev, + &genphy_10g_driver.mdiodrv.driver); +} +EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g); + /** * phy_detach - detach a PHY device from its network device * @phydev: target phy_device struct @@ -1308,8 +1338,8 @@ void phy_detach(struct phy_device *phydev) * from the generic driver so that there's a chance a * real driver could be loaded */ - if (phydev->mdio.dev.driver == &genphy_10g_driver.mdiodrv.driver || - phydev->mdio.dev.driver == &genphy_driver.mdiodrv.driver) + if (phy_driver_is_genphy(phydev) || + phy_driver_is_genphy_10g(phydev)) device_release_driver(&phydev->mdio.dev); /* -- cgit v1.2.3 From 4559dd248297cf8eb0318cff971d5f5c33660b6c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 15 Jan 2019 19:04:56 -0600 Subject: net: hns: Use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; struct boo entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + count * sizeof(struct boo), GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index 5d64519b9b1d..6bf346c11b25 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -788,8 +788,9 @@ int hns_rcb_common_get_cfg(struct dsaf_device *dsaf_dev, int ring_num = hns_rcb_get_ring_num(dsaf_dev); rcb_common = - devm_kzalloc(dsaf_dev->dev, sizeof(*rcb_common) + - ring_num * sizeof(struct ring_pair_cb), GFP_KERNEL); + devm_kzalloc(dsaf_dev->dev, + struct_size(rcb_common, ring_pair_cb, ring_num), + GFP_KERNEL); if (!rcb_common) { dev_err(dsaf_dev->dev, "rcb common devm_kzalloc fail!\n"); return -ENOMEM; -- cgit v1.2.3 From 13d0ab6750b20957ac1466da4e44dc0af746ff28 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 16 Jan 2019 08:07:38 +0100 Subject: net: phy: check return code when requesting PHY driver module When requesting the PHY driver module fails we'll bind the genphy driver later. This isn't obvious to the user and may cause, depending on the PHY, different types of issues. Therefore check the return code of request_module(). Note that we only check for failures in loading the module, not whether a module exists for the respective PHY ID. v2: - add comment explaining what is checked and what is not - return error from phy_device_create() if loading module fails Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index c02669270c41..ddb12f420940 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -546,12 +546,31 @@ static const struct device_type mdio_bus_phy_type = { .pm = MDIO_BUS_PHY_PM_OPS, }; +static int phy_request_driver_module(struct phy_device *dev, int phy_id) +{ + int ret; + + ret = request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, + MDIO_ID_ARGS(phy_id)); + /* we only check for failures in executing the usermode binary, + * not whether a PHY driver module exists for the PHY ID + */ + if (IS_ENABLED(CONFIG_MODULES) && ret < 0) { + phydev_err(dev, "error %d loading PHY driver module for ID 0x%08x\n", + ret, phy_id); + return ret; + } + + return 0; +} + struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, bool is_c45, struct phy_c45_device_ids *c45_ids) { struct phy_device *dev; struct mdio_device *mdiodev; + int ret = 0; /* We allocate the device, and initialize the default values */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -608,15 +627,21 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, if (!(c45_ids->devices_in_package & (1 << i))) continue; - request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, - MDIO_ID_ARGS(c45_ids->device_ids[i])); + ret = phy_request_driver_module(dev, + c45_ids->device_ids[i]); + if (ret) + break; } } else { - request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, - MDIO_ID_ARGS(phy_id)); + ret = phy_request_driver_module(dev, phy_id); } - device_initialize(&mdiodev->dev); + if (!ret) { + device_initialize(&mdiodev->dev); + } else { + kfree(dev); + dev = ERR_PTR(ret); + } return dev; } -- cgit v1.2.3 From 5fb1beeceab857d57312e9351d836f168b513027 Mon Sep 17 00:00:00 2001 From: Bert Kenward Date: Wed, 16 Jan 2019 10:00:39 +0000 Subject: sfc: extend MTD support for newer hardware The X2 family of NICs (based on the SFC9250) have additional MTD partitions for firmware and configuration. This includes partitions that are read-only. The NICs also have extended versions of the NVRAM interface, allowing more detailed status information to be returned. Signed-off-by: Bert Kenward Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 14 ++++++++--- drivers/net/ethernet/sfc/mcdi.c | 56 +++++++++++++++++++++++++++++++++++------ drivers/net/ethernet/sfc/mtd.c | 3 +++ 3 files changed, 63 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index b6a50058bb8d..ee42d4a887d7 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -6041,10 +6041,11 @@ static const struct efx_ef10_nvram_type_info efx_ef10_nvram_types[] = { { NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 0, 3, "sfc_exp_rom_cfg" }, { NVRAM_PARTITION_TYPE_LICENSE, 0, 0, "sfc_license" }, { NVRAM_PARTITION_TYPE_PHY_MIN, 0xff, 0, "sfc_phy_fw" }, - /* MUM and SUC firmware share the same partition type */ { NVRAM_PARTITION_TYPE_MUM_FIRMWARE, 0, 0, "sfc_mumfw" }, { NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 0, 0, "sfc_uefi" }, - { NVRAM_PARTITION_TYPE_STATUS, 0, 0, "sfc_status" } + { NVRAM_PARTITION_TYPE_DYNCONFIG_DEFAULTS, 0, 0, "sfc_dynamic_cfg_dflt" }, + { NVRAM_PARTITION_TYPE_ROMCONFIG_DEFAULTS, 0, 0, "sfc_exp_rom_cfg_dflt" }, + { NVRAM_PARTITION_TYPE_STATUS, 0, 0, "sfc_status" }, }; static int efx_ef10_mtd_probe_partition(struct efx_nic *efx, @@ -6071,8 +6072,15 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx, rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected); if (rc) return rc; + if (protected && + (type != NVRAM_PARTITION_TYPE_DYNCONFIG_DEFAULTS && + type != NVRAM_PARTITION_TYPE_ROMCONFIG_DEFAULTS)) + /* Hide protected partitions that don't provide defaults. */ + return -ENODEV; + if (protected) - return -ENODEV; /* hide it */ + /* Protected partitions are read only. */ + erase_size = 0; part->nvram_type = type; diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index dfad93fca0a6..295ec1787b9f 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -2074,22 +2074,26 @@ fail: static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type) { - MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN); + MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN); int rc; MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type); + MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_START_V2_IN_FLAGS, + NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, + 1); BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf), NULL, 0, NULL); + return rc; } static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, loff_t offset, u8 *buffer, size_t length) { - MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN); + MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_V2_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX)); size_t outlen; @@ -2098,6 +2102,8 @@ static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type); MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset); MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length); + MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_V2_MODE, + MC_CMD_NVRAM_READ_IN_V2_DEFAULT); rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); @@ -2147,15 +2153,51 @@ static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type) { - MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN); - int rc; + MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN); + MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN); + size_t outlen; + int rc, rc2; MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type); - - BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0); + /* Always set this flag. Old firmware ignores it */ + MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_FINISH_V2_IN_FLAGS, + NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, + 1); rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf), - NULL, 0, NULL); + outbuf, sizeof(outbuf), &outlen); + if (!rc && outlen >= MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) { + rc2 = MCDI_DWORD(outbuf, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE); + if (rc2 != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) + netif_err(efx, drv, efx->net_dev, + "NVRAM update failed verification with code 0x%x\n", + rc2); + switch (rc2) { + case MC_CMD_NVRAM_VERIFY_RC_SUCCESS: + break; + case MC_CMD_NVRAM_VERIFY_RC_CMS_CHECK_FAILED: + case MC_CMD_NVRAM_VERIFY_RC_MESSAGE_DIGEST_CHECK_FAILED: + case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHECK_FAILED: + case MC_CMD_NVRAM_VERIFY_RC_TRUSTED_APPROVERS_CHECK_FAILED: + case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHAIN_CHECK_FAILED: + rc = -EIO; + break; + case MC_CMD_NVRAM_VERIFY_RC_INVALID_CMS_FORMAT: + case MC_CMD_NVRAM_VERIFY_RC_BAD_MESSAGE_DIGEST: + rc = -EINVAL; + break; + case MC_CMD_NVRAM_VERIFY_RC_NO_VALID_SIGNATURES: + case MC_CMD_NVRAM_VERIFY_RC_NO_TRUSTED_APPROVERS: + case MC_CMD_NVRAM_VERIFY_RC_NO_SIGNATURE_MATCH: + rc = -EPERM; + break; + default: + netif_err(efx, drv, efx->net_dev, + "Unknown response to NVRAM_UPDATE_FINISH\n"); + rc = -EIO; + } + } + return rc; } diff --git a/drivers/net/ethernet/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c index 4ac30b6e5dab..0d03e0577d85 100644 --- a/drivers/net/ethernet/sfc/mtd.c +++ b/drivers/net/ethernet/sfc/mtd.c @@ -66,6 +66,9 @@ int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts, part->mtd.writesize = 1; + if (!(part->mtd.flags & MTD_NO_ERASE)) + part->mtd.flags |= MTD_WRITEABLE; + part->mtd.owner = THIS_MODULE; part->mtd.priv = efx; part->mtd.name = part->name; -- cgit v1.2.3 From aed13f2e00ce278f039b76e7ac84d419aff48ef6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 16 Jan 2019 11:23:33 +0100 Subject: net: dsa: lantiq_gswip: fix use-after-free on failed probe Make sure to disable and deregister the switch on late probe errors to avoid use-after-free when the device-resource-managed switch is freed. Fixes: 14fceff4771e ("net: dsa: Add Lantiq / Intel DSA driver for vrx200") Cc: stable # 4.20 Cc: Hauke Mehrtens Signed-off-by: Johan Hovold Reviewed-by: Andrew Lunn Acked-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/dsa/lantiq_gswip.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index 693a67f45bef..b06c41c98de9 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1099,7 +1099,7 @@ static int gswip_probe(struct platform_device *pdev) dev_err(dev, "wrong CPU port defined, HW only supports port: %i", priv->hw_info->cpu_port); err = -EINVAL; - goto mdio_bus; + goto disable_switch; } platform_set_drvdata(pdev, priv); @@ -1109,6 +1109,9 @@ static int gswip_probe(struct platform_device *pdev) (version & GSWIP_VERSION_MOD_MASK) >> GSWIP_VERSION_MOD_SHIFT); return 0; +disable_switch: + gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB); + dsa_unregister_switch(priv->ds); mdio_bus: if (mdio_np) mdiobus_unregister(priv->ds->slave_mii_bus); -- cgit v1.2.3 From c8cbcb0d8bd72d44fad1a5ddc348ac10e0fb1b37 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 16 Jan 2019 11:23:34 +0100 Subject: net: dsa: lantiq_gswip: fix OF child-node lookups Use the new of_get_compatible_child() helper to look up child nodes to avoid ever matching non-child nodes elsewhere in the tree. Also fix up the related struct device_node leaks. Fixes: 14fceff4771e ("net: dsa: Add Lantiq / Intel DSA driver for vrx200") Cc: stable # 4.20 Cc: Hauke Mehrtens Signed-off-by: Johan Hovold Reviewed-by: Andrew Lunn Acked-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/dsa/lantiq_gswip.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index b06c41c98de9..5792674dd4e4 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1069,10 +1069,10 @@ static int gswip_probe(struct platform_device *pdev) version = gswip_switch_r(priv, GSWIP_VERSION); /* bring up the mdio bus */ - gphy_fw_np = of_find_compatible_node(pdev->dev.of_node, NULL, - "lantiq,gphy-fw"); + gphy_fw_np = of_get_compatible_child(dev->of_node, "lantiq,gphy-fw"); if (gphy_fw_np) { err = gswip_gphy_fw_list(priv, gphy_fw_np, version); + of_node_put(gphy_fw_np); if (err) { dev_err(dev, "gphy fw probe failed\n"); return err; @@ -1080,13 +1080,12 @@ static int gswip_probe(struct platform_device *pdev) } /* bring up the mdio bus */ - mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL, - "lantiq,xrx200-mdio"); + mdio_np = of_get_compatible_child(dev->of_node, "lantiq,xrx200-mdio"); if (mdio_np) { err = gswip_mdio(priv, mdio_np); if (err) { dev_err(dev, "mdio probe failed\n"); - goto gphy_fw; + goto put_mdio_node; } } @@ -1115,7 +1114,8 @@ disable_switch: mdio_bus: if (mdio_np) mdiobus_unregister(priv->ds->slave_mii_bus); -gphy_fw: +put_mdio_node: + of_node_put(mdio_np); for (i = 0; i < priv->num_gphy_fw; i++) gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]); return err; @@ -1134,8 +1134,10 @@ static int gswip_remove(struct platform_device *pdev) dsa_unregister_switch(priv->ds); - if (priv->ds->slave_mii_bus) + if (priv->ds->slave_mii_bus) { mdiobus_unregister(priv->ds->slave_mii_bus); + of_node_put(priv->ds->slave_mii_bus->dev.of_node); + } for (i = 0; i < priv->num_gphy_fw; i++) gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]); -- cgit v1.2.3 From 8bb18f69c71f5fedaded2d0337dd8a0d15b51ea5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 16 Jan 2019 11:23:35 +0100 Subject: net: dsa: lantiq_gswip: drop bogus drvdata check The platform-device driver data is set on successful probe and will never be NULL on remove (or we have much bigger problems). Signed-off-by: Johan Hovold Reviewed-by: Andrew Lunn Acked-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/dsa/lantiq_gswip.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index 5792674dd4e4..27d092cab40e 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1126,9 +1126,6 @@ static int gswip_remove(struct platform_device *pdev) struct gswip_priv *priv = platform_get_drvdata(pdev); int i; - if (!priv) - return 0; - /* disable the switch */ gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB); -- cgit v1.2.3 From 43deda5408f913604bbca8c197f2cb25f22c4030 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 16 Jan 2019 20:49:25 +0100 Subject: davicom: Annotate implicit fall through in dm9000_set_io There is a plan to build the kernel with -Wimplicit-fallthrough and this place in the code produced a warning (W=1). This commit removes the following warning: include/linux/device.h:1480:5: warning: this statement may fall through [-Wimplicit-fallthrough=] drivers/net/ethernet/davicom/dm9000.c:397:3: note: in expansion of macro 'dev_dbg' drivers/net/ethernet/davicom/dm9000.c:398:2: note: here Signed-off-by: Mathieu Malaterre Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 0a82fcf16d35..c2586f44c29d 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -395,6 +395,7 @@ static void dm9000_set_io(struct board_info *db, int byte_width) case 3: dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n"); + /* fall through */ case 2: db->dumpblk = dm9000_dumpblk_16bit; db->outblk = dm9000_outblk_16bit; -- cgit v1.2.3 From 9b420eff9fcf69a85034c1e657a861de575c96e1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 16 Jan 2019 21:52:22 +0100 Subject: net: phy: micrel: use phy_read_mmd and phy_write_mmd This driver implements open-coded versions of phy_read_mmd() and phy_write_mmd() for KSZ9031. That's not needed, let's use the phylib functions directly. This is compile-tested only because I have no such hardware. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 43 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index c33384710d26..670698b7ef0e 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -426,9 +426,6 @@ static int ksz9021_config_init(struct phy_device *phydev) return 0; } -#define MII_KSZ9031RN_MMD_CTRL_REG 0x0d -#define MII_KSZ9031RN_MMD_REGDATA_REG 0x0e -#define OP_DATA 1 #define KSZ9031_PS_TO_REG 60 /* Extended registers */ @@ -446,24 +443,6 @@ static int ksz9021_config_init(struct phy_device *phydev) #define MII_KSZ9031RN_EDPD 0x23 #define MII_KSZ9031RN_EDPD_ENABLE BIT(0) -static int ksz9031_extended_write(struct phy_device *phydev, - u8 mode, u32 dev_addr, u32 regnum, u16 val) -{ - phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr); - phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum); - phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr); - return phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, val); -} - -static int ksz9031_extended_read(struct phy_device *phydev, - u8 mode, u32 dev_addr, u32 regnum) -{ - phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr); - phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum); - phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr); - return phy_read(phydev, MII_KSZ9031RN_MMD_REGDATA_REG); -} - static int ksz9031_of_load_skew_values(struct phy_device *phydev, const struct device_node *of_node, u16 reg, size_t field_sz, @@ -484,7 +463,7 @@ static int ksz9031_of_load_skew_values(struct phy_device *phydev, return 0; if (matches < numfields) - newval = ksz9031_extended_read(phydev, OP_DATA, 2, reg); + newval = phy_read_mmd(phydev, 2, reg); else newval = 0; @@ -498,7 +477,7 @@ static int ksz9031_of_load_skew_values(struct phy_device *phydev, << (field_sz * i)); } - return ksz9031_extended_write(phydev, OP_DATA, 2, reg, newval); + return phy_write_mmd(phydev, 2, reg, newval); } /* Center KSZ9031RNX FLP timing at 16ms. */ @@ -506,13 +485,13 @@ static int ksz9031_center_flp_timing(struct phy_device *phydev) { int result; - result = ksz9031_extended_write(phydev, OP_DATA, 0, - MII_KSZ9031RN_FLP_BURST_TX_HI, 0x0006); + result = phy_write_mmd(phydev, 0, MII_KSZ9031RN_FLP_BURST_TX_HI, + 0x0006); if (result) return result; - result = ksz9031_extended_write(phydev, OP_DATA, 0, - MII_KSZ9031RN_FLP_BURST_TX_LO, 0x1A80); + result = phy_write_mmd(phydev, 0, MII_KSZ9031RN_FLP_BURST_TX_LO, + 0x1A80); if (result) return result; @@ -524,11 +503,11 @@ static int ksz9031_enable_edpd(struct phy_device *phydev) { int reg; - reg = ksz9031_extended_read(phydev, OP_DATA, 0x1C, MII_KSZ9031RN_EDPD); + reg = phy_read_mmd(phydev, 0x1C, MII_KSZ9031RN_EDPD); if (reg < 0) return reg; - return ksz9031_extended_write(phydev, OP_DATA, 0x1C, MII_KSZ9031RN_EDPD, - reg | MII_KSZ9031RN_EDPD_ENABLE); + return phy_write_mmd(phydev, 0x1C, MII_KSZ9031RN_EDPD, + reg | MII_KSZ9031RN_EDPD_ENABLE); } static int ksz9031_config_init(struct phy_device *phydev) @@ -654,7 +633,7 @@ static int ksz9131_of_load_skew_values(struct phy_device *phydev, return 0; if (matches < numfields) - newval = ksz9031_extended_read(phydev, OP_DATA, 2, reg); + newval = phy_read_mmd(phydev, 2, reg); else newval = 0; @@ -668,7 +647,7 @@ static int ksz9131_of_load_skew_values(struct phy_device *phydev, << (field_sz * i)); } - return ksz9031_extended_write(phydev, OP_DATA, 2, reg, newval); + return phy_write_mmd(phydev, 2, reg, newval); } static int ksz9131_config_init(struct phy_device *phydev) -- cgit v1.2.3 From c2b200e0bac0a0667f2de18e0806fcf71b745080 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:30 +0000 Subject: vxlan: Move up vxlan_fdb_free(), vxlan_fdb_destroy() These functions will be needed for rollbacks of vetoed FDB entries. Move them up so that they are visible at their intended point of use. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 59 ++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 5209ee9aac47..e4ace5e917a7 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -826,6 +826,35 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, return 0; } +static void vxlan_fdb_free(struct rcu_head *head) +{ + struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu); + struct vxlan_rdst *rd, *nd; + + list_for_each_entry_safe(rd, nd, &f->remotes, list) { + dst_cache_destroy(&rd->dst_cache); + kfree(rd); + } + kfree(f); +} + +static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, + bool do_notify, bool swdev_notify) +{ + struct vxlan_rdst *rd; + + netdev_dbg(vxlan->dev, "delete %pM\n", f->eth_addr); + + --vxlan->addrcnt; + if (do_notify) + list_for_each_entry(rd, &f->remotes, list) + vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH, + swdev_notify); + + hlist_del_rcu(&f->hlist); + call_rcu(&f->rcu, vxlan_fdb_free); +} + /* Add new entry to forwarding table -- assumes lock held */ static int vxlan_fdb_update(struct vxlan_dev *vxlan, const u8 *mac, union vxlan_addr *ip, @@ -912,36 +941,6 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, return 0; } -static void vxlan_fdb_free(struct rcu_head *head) -{ - struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu); - struct vxlan_rdst *rd, *nd; - - list_for_each_entry_safe(rd, nd, &f->remotes, list) { - dst_cache_destroy(&rd->dst_cache); - kfree(rd); - } - kfree(f); -} - -static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, - bool do_notify, bool swdev_notify) -{ - struct vxlan_rdst *rd; - - netdev_dbg(vxlan->dev, - "delete %pM\n", f->eth_addr); - - --vxlan->addrcnt; - if (do_notify) - list_for_each_entry(rd, &f->remotes, list) - vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH, - swdev_notify); - - hlist_del_rcu(&f->hlist); - call_rcu(&f->rcu, vxlan_fdb_free); -} - static void vxlan_dst_free(struct rcu_head *head) { struct vxlan_rdst *rd = container_of(head, struct vxlan_rdst, rcu); -- cgit v1.2.3 From a76d1ca296a7eefba5d186014fc4cd14ee98c28b Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:32 +0000 Subject: vxlan: Split vxlan_fdb_update() in two In order to make it easier to implement rollbacks after FDB update vetoing, separate the FDB update code to two parts: one that deals with updates of existing FDB entries, and one that creates new entries. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 158 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 97 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e4ace5e917a7..aeaa429229c7 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -855,92 +855,128 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, call_rcu(&f->rcu, vxlan_fdb_free); } -/* Add new entry to forwarding table -- assumes lock held */ -static int vxlan_fdb_update(struct vxlan_dev *vxlan, - const u8 *mac, union vxlan_addr *ip, - __u16 state, __u16 flags, - __be16 port, __be32 src_vni, __be32 vni, - __u32 ifindex, __u16 ndm_flags, - bool swdev_notify) +static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, + union vxlan_addr *ip, + __u16 state, __u16 flags, + __be16 port, __be32 vni, + __u32 ifindex, __u16 ndm_flags, + struct vxlan_fdb *f, + bool swdev_notify) { __u16 fdb_flags = (ndm_flags & ~NTF_USE); struct vxlan_rdst *rd = NULL; - struct vxlan_fdb *f; int notify = 0; int rc; - f = __vxlan_find_mac(vxlan, mac, src_vni); - if (f) { - if (flags & NLM_F_EXCL) { - netdev_dbg(vxlan->dev, - "lost race to create %pM\n", mac); - return -EEXIST; - } - - /* Do not allow an externally learned entry to take over an - * entry added by the user. - */ - if (!(fdb_flags & NTF_EXT_LEARNED) || - !(f->flags & NTF_VXLAN_ADDED_BY_USER)) { - if (f->state != state) { - f->state = state; - f->updated = jiffies; - notify = 1; - } - if (f->flags != fdb_flags) { - f->flags = fdb_flags; - f->updated = jiffies; - notify = 1; - } + /* Do not allow an externally learned entry to take over an entry added + * by the user. + */ + if (!(fdb_flags & NTF_EXT_LEARNED) || + !(f->flags & NTF_VXLAN_ADDED_BY_USER)) { + if (f->state != state) { + f->state = state; + f->updated = jiffies; + notify = 1; } - - if ((flags & NLM_F_REPLACE)) { - /* Only change unicasts */ - if (!(is_multicast_ether_addr(f->eth_addr) || - is_zero_ether_addr(f->eth_addr))) { - notify |= vxlan_fdb_replace(f, ip, port, vni, - ifindex); - } else - return -EOPNOTSUPP; + if (f->flags != fdb_flags) { + f->flags = fdb_flags; + f->updated = jiffies; + notify = 1; } - if ((flags & NLM_F_APPEND) && - (is_multicast_ether_addr(f->eth_addr) || - is_zero_ether_addr(f->eth_addr))) { - rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); + } - if (rc < 0) - return rc; + if ((flags & NLM_F_REPLACE)) { + /* Only change unicasts */ + if (!(is_multicast_ether_addr(f->eth_addr) || + is_zero_ether_addr(f->eth_addr))) { + rc = vxlan_fdb_replace(f, ip, port, vni, + ifindex); notify |= rc; - } - - if (ndm_flags & NTF_USE) - f->used = jiffies; - } else { - if (!(flags & NLM_F_CREATE)) - return -ENOENT; - - /* Disallow replace to add a multicast entry */ - if ((flags & NLM_F_REPLACE) && - (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac))) + } else { return -EOPNOTSUPP; + } + } + if ((flags & NLM_F_APPEND) && + (is_multicast_ether_addr(f->eth_addr) || + is_zero_ether_addr(f->eth_addr))) { + rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); - netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); - rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni, - vni, ifindex, fdb_flags, &f); if (rc < 0) return rc; - notify = 1; + notify |= rc; } + if (ndm_flags & NTF_USE) + f->used = jiffies; + if (notify) { if (rd == NULL) rd = first_remote_rtnl(f); + vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify); } return 0; } +static int vxlan_fdb_update_create(struct vxlan_dev *vxlan, + const u8 *mac, union vxlan_addr *ip, + __u16 state, __u16 flags, + __be16 port, __be32 src_vni, __be32 vni, + __u32 ifindex, __u16 ndm_flags, + bool swdev_notify) +{ + __u16 fdb_flags = (ndm_flags & ~NTF_USE); + struct vxlan_fdb *f; + int rc; + + /* Disallow replace to add a multicast entry */ + if ((flags & NLM_F_REPLACE) && + (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac))) + return -EOPNOTSUPP; + + netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); + rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni, + vni, ifindex, fdb_flags, &f); + if (rc < 0) + return rc; + + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH, + swdev_notify); + return 0; +} + +/* Add new entry to forwarding table -- assumes lock held */ +static int vxlan_fdb_update(struct vxlan_dev *vxlan, + const u8 *mac, union vxlan_addr *ip, + __u16 state, __u16 flags, + __be16 port, __be32 src_vni, __be32 vni, + __u32 ifindex, __u16 ndm_flags, + bool swdev_notify) +{ + struct vxlan_fdb *f; + + f = __vxlan_find_mac(vxlan, mac, src_vni); + if (f) { + if (flags & NLM_F_EXCL) { + netdev_dbg(vxlan->dev, + "lost race to create %pM\n", mac); + return -EEXIST; + } + + return vxlan_fdb_update_existing(vxlan, ip, state, flags, port, + vni, ifindex, ndm_flags, f, + swdev_notify); + } else { + if (!(flags & NLM_F_CREATE)) + return -ENOENT; + + return vxlan_fdb_update_create(vxlan, mac, ip, state, flags, + port, src_vni, vni, ifindex, + ndm_flags, swdev_notify); + } +} + static void vxlan_dst_free(struct rcu_head *head) { struct vxlan_rdst *rd = container_of(head, struct vxlan_rdst, rcu); -- cgit v1.2.3 From ccdfd4f71d10937504cac8663cb1782063319e39 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:34 +0000 Subject: vxlan: Have vxlan_fdb_replace() save original rdst value To enable rollbacks after vetoed FDB updates, extend vxlan_fdb_replace() to take an additional argument where it should store the original values of a modified rdst. Update the sole caller. The following patch will make use of the saved value. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index aeaa429229c7..1c8d8c8e0961 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -625,7 +625,7 @@ EXPORT_SYMBOL_GPL(vxlan_fdb_clear_offload); /* Replace destination of unicast mac */ static int vxlan_fdb_replace(struct vxlan_fdb *f, union vxlan_addr *ip, __be16 port, __be32 vni, - __u32 ifindex) + __u32 ifindex, struct vxlan_rdst *oldrd) { struct vxlan_rdst *rd; @@ -637,6 +637,7 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f, if (!rd) return 0; + *oldrd = *rd; dst_cache_reset(&rd->dst_cache); rd->remote_ip = *ip; rd->remote_port = port; @@ -865,6 +866,7 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, { __u16 fdb_flags = (ndm_flags & ~NTF_USE); struct vxlan_rdst *rd = NULL; + struct vxlan_rdst oldrd; int notify = 0; int rc; @@ -890,7 +892,7 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, if (!(is_multicast_ether_addr(f->eth_addr) || is_zero_ether_addr(f->eth_addr))) { rc = vxlan_fdb_replace(f, ip, port, vni, - ifindex); + ifindex, &oldrd); notify |= rc; } else { return -EOPNOTSUPP; -- cgit v1.2.3 From 61f46fe8c646c1cc7810ee0963d7870b6d901a96 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:38 +0000 Subject: vxlan: Allow vetoing of FDB notifications Change vxlan_fdb_switchdev_call_notifiers() to return the result from calling switchdev notifiers. Propagate the error number up the stack. In vxlan_fdb_update_existing() and vxlan_fdb_update_create() add rollbacks to clean up the work that was done before the veto. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 64 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 1c8d8c8e0961..92904ee16053 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -375,32 +375,38 @@ static void vxlan_fdb_switchdev_notifier_info(const struct vxlan_dev *vxlan, fdb_info->added_by_user = fdb->flags & NTF_VXLAN_ADDED_BY_USER; } -static void vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, - struct vxlan_fdb *fdb, - struct vxlan_rdst *rd, - bool adding) +static int vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, + struct vxlan_fdb *fdb, + struct vxlan_rdst *rd, + bool adding) { struct switchdev_notifier_vxlan_fdb_info info; enum switchdev_notifier_type notifier_type; + int ret; if (WARN_ON(!rd)) - return; + return 0; notifier_type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE : SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE; vxlan_fdb_switchdev_notifier_info(vxlan, fdb, rd, &info); - call_switchdev_notifiers(notifier_type, vxlan->dev, - &info.info); + ret = call_switchdev_notifiers(notifier_type, vxlan->dev, + &info.info); + return notifier_to_errno(ret); } -static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, - struct vxlan_rdst *rd, int type, bool swdev_notify) +static int vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, + struct vxlan_rdst *rd, int type, bool swdev_notify) { + int err; + if (swdev_notify) { switch (type) { case RTM_NEWNEIGH: - vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, - true); + err = vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, + true); + if (err) + return err; break; case RTM_DELNEIGH: vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, @@ -410,6 +416,7 @@ static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, } __vxlan_fdb_notify(vxlan, fdb, rd, type); + return 0; } static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa) @@ -868,7 +875,8 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, struct vxlan_rdst *rd = NULL; struct vxlan_rdst oldrd; int notify = 0; - int rc; + int rc = 0; + int err; /* Do not allow an externally learned entry to take over an entry added * by the user. @@ -915,10 +923,20 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, if (rd == NULL) rd = first_remote_rtnl(f); - vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify); + err = vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, + swdev_notify); + if (err) + goto err_notify; } return 0; + +err_notify: + if ((flags & NLM_F_REPLACE) && rc) + *rd = oldrd; + else if ((flags & NLM_F_APPEND) && rc) + list_del_rcu(&rd->list); + return err; } static int vxlan_fdb_update_create(struct vxlan_dev *vxlan, @@ -943,9 +961,16 @@ static int vxlan_fdb_update_create(struct vxlan_dev *vxlan, if (rc < 0) return rc; - vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH, - swdev_notify); + rc = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH, + swdev_notify); + if (rc) + goto err_notify; + return 0; + +err_notify: + vxlan_fdb_destroy(vxlan, f, false, false); + return rc; } /* Add new entry to forwarding table -- assumes lock held */ @@ -3515,9 +3540,12 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev, goto errout; /* notify default fdb entry */ - if (f) - vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH, - true); + if (f) { + err = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), + RTM_NEWNEIGH, true); + if (err) + goto errout; + } list_add(&vxlan->next, &vn->vxlan_list); return 0; -- cgit v1.2.3 From 8db9427d52b894276383091883b6a8bc5bb0c14d Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:39 +0000 Subject: vxlan: changelink: Inline vxlan_dev_configure() The changelink operation may cause change in remote address, and therefore an FDB update, which can be vetoed. To properly handle vetoing, vxlan_changelink() needs to be gradually updated. In this patch simply replace vxlan_dev_configure() with the two constituent calls. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 92904ee16053..f2f419c60dfe 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3793,6 +3793,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *dst = &vxlan->default_dst; unsigned long old_age_interval; + struct net_device *lowerdev; struct vxlan_rdst old_dst; struct vxlan_config conf; int err; @@ -3805,10 +3806,13 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], old_age_interval = vxlan->cfg.age_interval; memcpy(&old_dst, dst, sizeof(struct vxlan_rdst)); - err = vxlan_dev_configure(vxlan->net, dev, &conf, true, extack); + err = vxlan_config_validate(vxlan->net, &conf, &lowerdev, + vxlan, extack); if (err) return err; + vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true); + if (old_age_interval != vxlan->cfg.age_interval) mod_timer(&vxlan->age_timer, jiffies); -- cgit v1.2.3 From 038a5a99e95214d0549401c74711152d9869ead3 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:41 +0000 Subject: vxlan: changelink: Postpone vxlan_config_apply() When an FDB entry is vetoed, it is necessary to unroll the changes that have already been done. To avoid having to unroll vxlan_config_apply(), postpone the call after the point where the vetoing takes place. Since the call can't fail, it doesn't necessitate any cleanups in the preceding FDB update logic. Correspondingly, move down the mod_timer() call as well. References to *dst need to be replaced with references to conf. Additionally, old_dst and old_age_interval are not necessary anymore, and therefore drop them. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index f2f419c60dfe..51e10f47d4f1 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3792,9 +3792,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *dst = &vxlan->default_dst; - unsigned long old_age_interval; struct net_device *lowerdev; - struct vxlan_rdst old_dst; struct vxlan_config conf; int err; @@ -3803,40 +3801,31 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], if (err) return err; - old_age_interval = vxlan->cfg.age_interval; - memcpy(&old_dst, dst, sizeof(struct vxlan_rdst)); - err = vxlan_config_validate(vxlan->net, &conf, &lowerdev, vxlan, extack); if (err) return err; - vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true); - - if (old_age_interval != vxlan->cfg.age_interval) - mod_timer(&vxlan->age_timer, jiffies); - /* handle default dst entry */ - if (!vxlan_addr_equal(&dst->remote_ip, &old_dst.remote_ip)) { + if (!vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip)) { spin_lock_bh(&vxlan->hash_lock); - if (!vxlan_addr_any(&old_dst.remote_ip)) + if (!vxlan_addr_any(&dst->remote_ip)) __vxlan_fdb_delete(vxlan, all_zeros_mac, - old_dst.remote_ip, + dst->remote_ip, vxlan->cfg.dst_port, - old_dst.remote_vni, - old_dst.remote_vni, - old_dst.remote_ifindex, + dst->remote_vni, + dst->remote_vni, + dst->remote_ifindex, true); - if (!vxlan_addr_any(&dst->remote_ip)) { + if (!vxlan_addr_any(&conf.remote_ip)) { err = vxlan_fdb_update(vxlan, all_zeros_mac, - &dst->remote_ip, + &conf.remote_ip, NUD_REACHABLE | NUD_PERMANENT, NLM_F_APPEND | NLM_F_CREATE, vxlan->cfg.dst_port, - dst->remote_vni, - dst->remote_vni, - dst->remote_ifindex, + conf.vni, conf.vni, + conf.remote_ifindex, NTF_SELF, true); if (err) { spin_unlock_bh(&vxlan->hash_lock); @@ -3846,6 +3835,10 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], spin_unlock_bh(&vxlan->hash_lock); } + if (conf.age_interval != vxlan->cfg.age_interval) + mod_timer(&vxlan->age_timer, jiffies); + + vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true); return 0; } -- cgit v1.2.3 From 1cdc98c2711e42d956c4a5ce525d3f8e90c58f9e Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:43 +0000 Subject: vxlan: changelink: Delete remote after update If a change in remote address prompts a change in a default FDB entry, that change might be vetoed. If that happens, it would then be necessary to reinstate the already-removed default FDB entry corresponding to the previous remote address. Instead, arrange to have the previous address removed only after the FDB is successfully vetted. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 51e10f47d4f1..83f65eb3085f 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3809,15 +3809,6 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], /* handle default dst entry */ if (!vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip)) { spin_lock_bh(&vxlan->hash_lock); - if (!vxlan_addr_any(&dst->remote_ip)) - __vxlan_fdb_delete(vxlan, all_zeros_mac, - dst->remote_ip, - vxlan->cfg.dst_port, - dst->remote_vni, - dst->remote_vni, - dst->remote_ifindex, - true); - if (!vxlan_addr_any(&conf.remote_ip)) { err = vxlan_fdb_update(vxlan, all_zeros_mac, &conf.remote_ip, @@ -3832,6 +3823,14 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], return err; } } + if (!vxlan_addr_any(&dst->remote_ip)) + __vxlan_fdb_delete(vxlan, all_zeros_mac, + dst->remote_ip, + vxlan->cfg.dst_port, + dst->remote_vni, + dst->remote_vni, + dst->remote_ifindex, + true); spin_unlock_bh(&vxlan->hash_lock); } -- cgit v1.2.3 From 87b0984ebfabafcfe959e52ca5cdab5eeb2d60c0 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:50 +0000 Subject: net: Add extack argument to ndo_fdb_add() Drivers may not be able to support certain FDB entries, and an error code is insufficient to give clear hints as to the reasons of rejection. In order to make it possible to communicate the rejection reason, extend ndo_fdb_add() with an extack argument. Adapt the existing implementations of ndo_fdb_add() to take the parameter (and ignore it). Pass the extack parameter when invoking ndo_fdb_add() from rtnl_fdb_add(). Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 ++- drivers/net/ethernet/intel/ice/ice_main.c | 3 ++- drivers/net/ethernet/intel/igb/igb_main.c | 3 ++- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 ++- drivers/net/ethernet/mscc/ocelot.c | 3 ++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 3 ++- drivers/net/macvlan.c | 3 ++- drivers/net/vxlan.c | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f52e2c46e6a7..0ee641c41be4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11644,7 +11644,8 @@ static int i40e_get_phys_port_id(struct net_device *netdev, static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags) + u16 flags, + struct netlink_ext_ack *extack) { struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_pf *pf = np->vsi->back; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f4bf6bda32a9..48f033928aa2 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2438,7 +2438,8 @@ static void ice_set_rx_mode(struct net_device *netdev) */ static int ice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[], struct net_device *dev, const unsigned char *addr, - u16 vid, u16 flags) + u16 vid, u16 flags, + struct netlink_ext_ack *extack) { int err; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 87bdf1604ae2..3615e2e52399 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2486,7 +2486,8 @@ static int igb_set_features(struct net_device *netdev, static int igb_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags) + u16 flags, + struct netlink_ext_ack *extack) { /* guarantee we can provide a unique filter for the unicast address */ if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index daff8183534b..b53087a980ef 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -9910,7 +9910,8 @@ static void ixgbe_del_udp_tunnel_port(struct net_device *dev, static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags) + u16 flags, + struct netlink_ext_ack *extack) { /* guarantee we can provide a unique filter for the unicast address */ if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) { diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 215a45374d7b..c6a575eb0ff5 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -721,7 +721,8 @@ static void ocelot_get_stats64(struct net_device *dev, static int ocelot_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, - u16 vid, u16 flags) + u16 vid, u16 flags, + struct netlink_ext_ack *extack) { struct ocelot_port *port = netdev_priv(dev); struct ocelot *ocelot = port->ocelot; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 16d0479f6891..7a873002e626 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -396,7 +396,8 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *netdev, - const unsigned char *addr, u16 vid, u16 flags) + const unsigned char *addr, u16 vid, u16 flags, + struct netlink_ext_ack *extack) { struct qlcnic_adapter *adapter = netdev_priv(netdev); int err = 0; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index fc726ce4c164..084a1b3fbc80 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -963,7 +963,8 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev, static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags) + u16 flags, + struct netlink_ext_ack *extack) { struct macvlan_dev *vlan = netdev_priv(dev); int err = -EINVAL; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 83f65eb3085f..11f38fd71678 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1087,7 +1087,8 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, /* Add static entry (via netlink) */ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, u16 vid, u16 flags) + const unsigned char *addr, u16 vid, u16 flags, + struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan = netdev_priv(dev); /* struct net *net = dev_net(vxlan->dev); */ -- cgit v1.2.3 From d907f58fa90f0fcba1268eab24b1e0997e0d1e22 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:52 +0000 Subject: mlxsw: Add extack to mlxsw_sp_nve_ops.fdb_replay A follow-up patch will extend vxlan_fdb_replay() with an extack argument. Extend the fdb_replay callback in mlxsw likewise so that the argument is ready for the vxlan conversion. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h | 3 ++- drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c index 9019548d731b..94e07767f18e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -841,7 +841,7 @@ int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, nve->config = config; - err = ops->fdb_replay(params->dev, params->vni); + err = ops->fdb_replay(params->dev, params->vni, extack); if (err) { NL_SET_ERR_MSG_MOD(extack, "Failed to offload the FDB"); goto err_fdb_replay; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h index 02937ea95bc3..20d99b41611d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h @@ -41,7 +41,8 @@ struct mlxsw_sp_nve_ops { int (*init)(struct mlxsw_sp_nve *nve, const struct mlxsw_sp_nve_config *config); void (*fini)(struct mlxsw_sp_nve *nve); - int (*fdb_replay)(const struct net_device *nve_dev, __be32 vni); + int (*fdb_replay)(const struct net_device *nve_dev, __be32 vni, + struct netlink_ext_ack *extack); void (*fdb_clear_offload)(const struct net_device *nve_dev, __be32 vni); }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c index 74e564c4ac19..bc565f2aa121 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c @@ -212,7 +212,8 @@ static void mlxsw_sp1_nve_vxlan_fini(struct mlxsw_sp_nve *nve) } static int -mlxsw_sp_nve_vxlan_fdb_replay(const struct net_device *nve_dev, __be32 vni) +mlxsw_sp_nve_vxlan_fdb_replay(const struct net_device *nve_dev, __be32 vni, + struct netlink_ext_ack *extack) { if (WARN_ON(!netif_is_vxlan(nve_dev))) return -EINVAL; -- cgit v1.2.3 From 4c59b7d16096e5e2cfbc7f8cba972eb72f6b96c0 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:54 +0000 Subject: vxlan: Add extack to switchdev operations There are four sources of VXLAN switchdev notifier calls: - the changelink() link operation, which already supports extack, - ndo_fdb_add() which got extack support in a previous patch, - FDB updates due to packet forwarding, - and vxlan_fdb_replay(). Extend vxlan_fdb_switchdev_call_notifiers() to include extack in the switchdev message that it sends, and propagate the argument upwards to the callers. For the first two cases, pass in the extack gotten through the operation. For case #3, pass in NULL. To cover the last case, extend vxlan_fdb_replay() to take extack argument, which might come from whatever operation necessitated the FDB replay. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c | 3 +- drivers/net/vxlan.c | 68 +++++++++++++--------- 2 files changed, 42 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c index bc565f2aa121..9ba0b83bd949 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c @@ -217,7 +217,8 @@ mlxsw_sp_nve_vxlan_fdb_replay(const struct net_device *nve_dev, __be32 vni, { if (WARN_ON(!netif_is_vxlan(nve_dev))) return -EINVAL; - return vxlan_fdb_replay(nve_dev, vni, &mlxsw_sp_switchdev_notifier); + return vxlan_fdb_replay(nve_dev, vni, &mlxsw_sp_switchdev_notifier, + extack); } static void diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 11f38fd71678..a9e90159bb61 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -361,10 +361,11 @@ errout: static void vxlan_fdb_switchdev_notifier_info(const struct vxlan_dev *vxlan, const struct vxlan_fdb *fdb, const struct vxlan_rdst *rd, + struct netlink_ext_ack *extack, struct switchdev_notifier_vxlan_fdb_info *fdb_info) { fdb_info->info.dev = vxlan->dev; - fdb_info->info.extack = NULL; + fdb_info->info.extack = extack; fdb_info->remote_ip = rd->remote_ip; fdb_info->remote_port = rd->remote_port; fdb_info->remote_vni = rd->remote_vni; @@ -378,7 +379,8 @@ static void vxlan_fdb_switchdev_notifier_info(const struct vxlan_dev *vxlan, static int vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, struct vxlan_rdst *rd, - bool adding) + bool adding, + struct netlink_ext_ack *extack) { struct switchdev_notifier_vxlan_fdb_info info; enum switchdev_notifier_type notifier_type; @@ -389,14 +391,15 @@ static int vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, notifier_type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE : SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE; - vxlan_fdb_switchdev_notifier_info(vxlan, fdb, rd, &info); + vxlan_fdb_switchdev_notifier_info(vxlan, fdb, rd, NULL, &info); ret = call_switchdev_notifiers(notifier_type, vxlan->dev, &info.info); return notifier_to_errno(ret); } static int vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, - struct vxlan_rdst *rd, int type, bool swdev_notify) + struct vxlan_rdst *rd, int type, bool swdev_notify, + struct netlink_ext_ack *extack) { int err; @@ -404,13 +407,13 @@ static int vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, switch (type) { case RTM_NEWNEIGH: err = vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, - true); + true, extack); if (err) return err; break; case RTM_DELNEIGH: vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, - false); + false, extack); break; } } @@ -430,7 +433,7 @@ static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa) .remote_vni = cpu_to_be32(VXLAN_N_VID), }; - vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH, true); + vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH, true, NULL); } static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN]) @@ -442,7 +445,7 @@ static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN]) memcpy(f.eth_addr, eth_addr, ETH_ALEN); - vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH, true); + vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH, true, NULL); } /* Hash Ethernet address */ @@ -552,7 +555,7 @@ int vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni, } rdst = first_remote_rcu(f); - vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, fdb_info); + vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, NULL, fdb_info); out: rcu_read_unlock(); @@ -563,19 +566,21 @@ EXPORT_SYMBOL_GPL(vxlan_fdb_find_uc); static int vxlan_fdb_notify_one(struct notifier_block *nb, const struct vxlan_dev *vxlan, const struct vxlan_fdb *f, - const struct vxlan_rdst *rdst) + const struct vxlan_rdst *rdst, + struct netlink_ext_ack *extack) { struct switchdev_notifier_vxlan_fdb_info fdb_info; int rc; - vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, &fdb_info); + vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, extack, &fdb_info); rc = nb->notifier_call(nb, SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE, &fdb_info); return notifier_to_errno(rc); } int vxlan_fdb_replay(const struct net_device *dev, __be32 vni, - struct notifier_block *nb) + struct notifier_block *nb, + struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan; struct vxlan_rdst *rdst; @@ -593,7 +598,8 @@ int vxlan_fdb_replay(const struct net_device *dev, __be32 vni, if (f->vni == vni) { list_for_each_entry(rdst, &f->remotes, list) { rc = vxlan_fdb_notify_one(nb, vxlan, - f, rdst); + f, rdst, + extack); if (rc) goto out; } @@ -857,7 +863,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, if (do_notify) list_for_each_entry(rd, &f->remotes, list) vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH, - swdev_notify); + swdev_notify, NULL); hlist_del_rcu(&f->hlist); call_rcu(&f->rcu, vxlan_fdb_free); @@ -869,7 +875,8 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, __be16 port, __be32 vni, __u32 ifindex, __u16 ndm_flags, struct vxlan_fdb *f, - bool swdev_notify) + bool swdev_notify, + struct netlink_ext_ack *extack) { __u16 fdb_flags = (ndm_flags & ~NTF_USE); struct vxlan_rdst *rd = NULL; @@ -924,7 +931,7 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, rd = first_remote_rtnl(f); err = vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, - swdev_notify); + swdev_notify, extack); if (err) goto err_notify; } @@ -944,7 +951,8 @@ static int vxlan_fdb_update_create(struct vxlan_dev *vxlan, __u16 state, __u16 flags, __be16 port, __be32 src_vni, __be32 vni, __u32 ifindex, __u16 ndm_flags, - bool swdev_notify) + bool swdev_notify, + struct netlink_ext_ack *extack) { __u16 fdb_flags = (ndm_flags & ~NTF_USE); struct vxlan_fdb *f; @@ -962,7 +970,7 @@ static int vxlan_fdb_update_create(struct vxlan_dev *vxlan, return rc; rc = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH, - swdev_notify); + swdev_notify, extack); if (rc) goto err_notify; @@ -979,7 +987,8 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, __u16 state, __u16 flags, __be16 port, __be32 src_vni, __be32 vni, __u32 ifindex, __u16 ndm_flags, - bool swdev_notify) + bool swdev_notify, + struct netlink_ext_ack *extack) { struct vxlan_fdb *f; @@ -993,14 +1002,14 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, return vxlan_fdb_update_existing(vxlan, ip, state, flags, port, vni, ifindex, ndm_flags, f, - swdev_notify); + swdev_notify, extack); } else { if (!(flags & NLM_F_CREATE)) return -ENOENT; return vxlan_fdb_update_create(vxlan, mac, ip, state, flags, port, src_vni, vni, ifindex, - ndm_flags, swdev_notify); + ndm_flags, swdev_notify, extack); } } @@ -1016,7 +1025,7 @@ static void vxlan_fdb_dst_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, struct vxlan_rdst *rd, bool swdev_notify) { list_del_rcu(&rd->list); - vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH, swdev_notify); + vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH, swdev_notify, NULL); call_rcu(&rd->rcu, vxlan_dst_free); } @@ -1118,7 +1127,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], err = vxlan_fdb_update(vxlan, addr, &ip, ndm->ndm_state, flags, port, src_vni, vni, ifindex, ndm->ndm_flags | NTF_VXLAN_ADDED_BY_USER, - true); + true, extack); spin_unlock_bh(&vxlan->hash_lock); return err; @@ -1286,7 +1295,7 @@ static bool vxlan_snoop(struct net_device *dev, rdst->remote_ip = *src_ip; f->updated = jiffies; - vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true); + vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL); } else { /* learned new entry */ spin_lock(&vxlan->hash_lock); @@ -1299,7 +1308,7 @@ static bool vxlan_snoop(struct net_device *dev, vxlan->cfg.dst_port, vni, vxlan->default_dst.remote_vni, - ifindex, NTF_SELF, true); + ifindex, NTF_SELF, true, NULL); spin_unlock(&vxlan->hash_lock); } @@ -3543,7 +3552,7 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev, /* notify default fdb entry */ if (f) { err = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), - RTM_NEWNEIGH, true); + RTM_NEWNEIGH, true, extack); if (err) goto errout; } @@ -3818,7 +3827,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], vxlan->cfg.dst_port, conf.vni, conf.vni, conf.remote_ifindex, - NTF_SELF, true); + NTF_SELF, true, extack); if (err) { spin_unlock_bh(&vxlan->hash_lock); return err; @@ -4113,8 +4122,11 @@ vxlan_fdb_external_learn_add(struct net_device *dev, struct switchdev_notifier_vxlan_fdb_info *fdb_info) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct netlink_ext_ack *extack; int err; + extack = switchdev_notifier_info_to_extack(&fdb_info->info); + spin_lock_bh(&vxlan->hash_lock); err = vxlan_fdb_update(vxlan, fdb_info->eth_addr, &fdb_info->remote_ip, NUD_REACHABLE, @@ -4124,7 +4136,7 @@ vxlan_fdb_external_learn_add(struct net_device *dev, fdb_info->remote_vni, fdb_info->remote_ifindex, NTF_USE | NTF_SELF | NTF_EXT_LEARNED, - false); + false, extack); spin_unlock_bh(&vxlan->hash_lock); return err; -- cgit v1.2.3 From 6685987c29582afc79b7fa3998dfbf36b4295791 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:56 +0000 Subject: switchdev: Add extack argument to call_switchdev_notifiers() A follow-up patch will enable vetoing of FDB entries. Make it possible to communicate details of why an FDB entry is not acceptable back to the user. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 6 ++++-- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 12 ++++++------ drivers/net/ethernet/rocker/rocker_main.c | 2 +- drivers/net/ethernet/rocker/rocker_ofdpa.c | 4 ++-- drivers/net/vxlan.c | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 98e5ffd71b91..042341c7f6b9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -7294,7 +7294,8 @@ static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) info.addr = mac; info.vid = vid; - call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info); + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info, + NULL); } static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops = { @@ -7381,7 +7382,8 @@ static void mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) info.addr = mac; info.vid = 0; - call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info); + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info, + NULL); } static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 0abbaa0fbf14..71aad9d4e160 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2443,7 +2443,7 @@ static void mlxsw_sp_fdb_vxlan_call_notifiers(struct net_device *dev, ether_addr_copy(info.eth_addr, mac); info.vni = vni; info.offloaded = adding; - call_switchdev_notifiers(type, dev, &info.info); + call_switchdev_notifiers(type, dev, &info.info, NULL); } static void mlxsw_sp_fdb_nve_call_notifiers(struct net_device *dev, @@ -2468,7 +2468,7 @@ mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type, info.addr = mac; info.vid = vid; info.offloaded = offloaded; - call_switchdev_notifiers(type, dev, &info.info); + call_switchdev_notifiers(type, dev, &info.info, NULL); } static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, @@ -2819,7 +2819,7 @@ mlxsw_sp_switchdev_bridge_vxlan_fdb_event(struct mlxsw_sp *mlxsw_sp, return; vxlan_fdb_info.offloaded = true; call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev, - &vxlan_fdb_info.info); + &vxlan_fdb_info.info, NULL); mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, vxlan_fdb_info.eth_addr, fdb_info->vid, dev, true); @@ -2832,7 +2832,7 @@ mlxsw_sp_switchdev_bridge_vxlan_fdb_event(struct mlxsw_sp *mlxsw_sp, false); vxlan_fdb_info.offloaded = false; call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev, - &vxlan_fdb_info.info); + &vxlan_fdb_info.info, NULL); break; } } @@ -2977,7 +2977,7 @@ mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp *mlxsw_sp, } vxlan_fdb_info->offloaded = true; call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev, - &vxlan_fdb_info->info); + &vxlan_fdb_info->info, NULL); mlxsw_sp_fid_put(fid); return; } @@ -2998,7 +2998,7 @@ mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp *mlxsw_sp, goto err_fdb_tunnel_uc_op; vxlan_fdb_info->offloaded = true; call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev, - &vxlan_fdb_info->info); + &vxlan_fdb_info->info, NULL); mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, vxlan_fdb_info->eth_addr, vid, dev, true); diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 6213827e3956..62a205eba9f7 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2725,7 +2725,7 @@ rocker_fdb_offload_notify(struct rocker_port *rocker_port, info.vid = recv_info->vid; info.offloaded = true; call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, - rocker_port->dev, &info.info); + rocker_port->dev, &info.info, NULL); } static void rocker_switchdev_event_work(struct work_struct *work) diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 6473cc68c2d5..bea7895930f6 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -1833,10 +1833,10 @@ static void ofdpa_port_fdb_learn_work(struct work_struct *work) rtnl_lock(); if (learned && removing) call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, - lw->ofdpa_port->dev, &info.info); + lw->ofdpa_port->dev, &info.info, NULL); else if (learned && !removing) call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, - lw->ofdpa_port->dev, &info.info); + lw->ofdpa_port->dev, &info.info, NULL); rtnl_unlock(); kfree(work); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index a9e90159bb61..ef45c3c925be 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -393,7 +393,7 @@ static int vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, : SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE; vxlan_fdb_switchdev_notifier_info(vxlan, fdb, rd, NULL, &info); ret = call_switchdev_notifiers(notifier_type, vxlan->dev, - &info.info); + &info.info, extack); return notifier_to_errno(ret); } -- cgit v1.2.3 From a40313d956d3d3124f44b63ba752383c948c8587 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 16 Jan 2019 23:06:58 +0000 Subject: mlxsw: spectrum: Add extack messages to VXLAN FDB rejection Annotate the rejections in mlxsw_sp_switchdev_vxlan_work_prepare() with textual reasons. Because this code ends up being invoked for FDB replay as well, drop the default message from there, so that the more accurate error message is not overwritten. Signed-off-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c | 4 +--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 25 ++++++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c index 94e07767f18e..1df164a4b06d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -842,10 +842,8 @@ int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, nve->config = config; err = ops->fdb_replay(params->dev, params->vni, extack); - if (err) { - NL_SET_ERR_MSG_MOD(extack, "Failed to offload the FDB"); + if (err) goto err_fdb_replay; - } return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 71aad9d4e160..8ab796e0c0d7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -3099,23 +3099,34 @@ mlxsw_sp_switchdev_vxlan_work_prepare(struct mlxsw_sp_switchdev_event_work * struct vxlan_dev *vxlan = netdev_priv(switchdev_work->dev); struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info; struct vxlan_config *cfg = &vxlan->cfg; + struct netlink_ext_ack *extack; + extack = switchdev_notifier_info_to_extack(info); vxlan_fdb_info = container_of(info, struct switchdev_notifier_vxlan_fdb_info, info); - if (vxlan_fdb_info->remote_port != cfg->dst_port) - return -EOPNOTSUPP; - if (vxlan_fdb_info->remote_vni != cfg->vni) + if (vxlan_fdb_info->remote_port != cfg->dst_port) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Non-default remote port is not supported"); return -EOPNOTSUPP; - if (vxlan_fdb_info->vni != cfg->vni) + } + if (vxlan_fdb_info->remote_vni != cfg->vni || + vxlan_fdb_info->vni != cfg->vni) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Non-default VNI is not supported"); return -EOPNOTSUPP; - if (vxlan_fdb_info->remote_ifindex) + } + if (vxlan_fdb_info->remote_ifindex) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Local interface is not supported"); return -EOPNOTSUPP; - if (is_multicast_ether_addr(vxlan_fdb_info->eth_addr)) + } + if (is_multicast_ether_addr(vxlan_fdb_info->eth_addr)) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Multicast MAC addresses not supported"); return -EOPNOTSUPP; - if (vxlan_addr_multicast(&vxlan_fdb_info->remote_ip)) + } + if (vxlan_addr_multicast(&vxlan_fdb_info->remote_ip)) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: FDB: Multicast destination IP is not supported"); return -EOPNOTSUPP; + } switchdev_work->vxlan_fdb_info = *vxlan_fdb_info; -- cgit v1.2.3 From 5191673b693251d8cd80eae360390df4be4ba6b3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 16 Jan 2019 17:08:17 +0000 Subject: wan: dscc4: fix various indentation issues There are some lines that have indentation issues, fix these. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/wan/dscc4.c | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index c0b0f525c87c..d5dc823f781e 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -456,16 +456,16 @@ static int state_check(u32 state, struct dscc4_dev_priv *dpriv, int ret = 0; if (debug > 1) { - if (SOURCE_ID(state) != dpriv->dev_id) { - printk(KERN_DEBUG "%s (%s): Source Id=%d, state=%08x\n", - dev->name, msg, SOURCE_ID(state), state ); + if (SOURCE_ID(state) != dpriv->dev_id) { + printk(KERN_DEBUG "%s (%s): Source Id=%d, state=%08x\n", + dev->name, msg, SOURCE_ID(state), state); ret = -1; - } - if (state & 0x0df80c00) { - printk(KERN_DEBUG "%s (%s): state=%08x (UFO alert)\n", - dev->name, msg, state); + } + if (state & 0x0df80c00) { + printk(KERN_DEBUG "%s (%s): state=%08x (UFO alert)\n", + dev->name, msg, state); ret = -1; - } + } } return ret; } @@ -1760,25 +1760,25 @@ try: } else { /* SccEvt */ if (debug > 1) { //FIXME: verifier la presence de tous les evenements - static struct { - u32 mask; - const char *irq_name; - } evts[] = { - { 0x00008000, "TIN"}, - { 0x00000020, "RSC"}, - { 0x00000010, "PCE"}, - { 0x00000008, "PLLA"}, - { 0, NULL} - }, *evt; - - for (evt = evts; evt->irq_name; evt++) { - if (state & evt->mask) { + static struct { + u32 mask; + const char *irq_name; + } evts[] = { + { 0x00008000, "TIN"}, + { 0x00000020, "RSC"}, + { 0x00000010, "PCE"}, + { 0x00000008, "PLLA"}, + { 0, NULL} + }, *evt; + + for (evt = evts; evt->irq_name; evt++) { + if (state & evt->mask) { printk(KERN_DEBUG "%s: %s\n", - dev->name, evt->irq_name); - if (!(state &= ~evt->mask)) - goto try; + dev->name, evt->irq_name); + if (!(state &= ~evt->mask)) + goto try; + } } - } } else { if (!(state &= ~0x0000c03c)) goto try; -- cgit v1.2.3 From 68d7431553a0cd05bce98d1c1d3fc56b3a1807c0 Mon Sep 17 00:00:00 2001 From: Ioana Ciocoi Radulescu Date: Wed, 16 Jan 2019 16:51:44 +0000 Subject: dpaa2-eth: Fix ndo_stop routine In the current implementation, on interface down we disabled NAPI and then manually drained any remaining ingress frames. This could lead to a situation when, under heavy traffic, the data availability notification for some of the channels would not get rearmed correctly. Change the implementation such that we let all remaining ingress frames be processed as usual and only disable NAPI once the hardware queues are empty. We also add a wait on the Tx side, to allow hardware time to process all in-flight Tx frames before issueing the disable command. Signed-off-by: Ioana Radulescu Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 68 ++++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 1ca9a18139ec..ecf92189b0a4 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1243,34 +1243,36 @@ enable_err: return err; } -/* The DPIO store must be empty when we call this, - * at the end of every NAPI cycle. - */ -static u32 drain_channel(struct dpaa2_eth_channel *ch) +/* Total number of in-flight frames on ingress queues */ +static u32 ingress_fq_count(struct dpaa2_eth_priv *priv) { - u32 drained = 0, total = 0; + struct dpaa2_eth_fq *fq; + u32 fcnt = 0, bcnt = 0, total = 0; + int i, err; - do { - pull_channel(ch); - drained = consume_frames(ch, NULL); - total += drained; - } while (drained); + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + err = dpaa2_io_query_fq_count(NULL, fq->fqid, &fcnt, &bcnt); + if (err) { + netdev_warn(priv->net_dev, "query_fq_count failed"); + break; + } + total += fcnt; + } return total; } -static u32 drain_ingress_frames(struct dpaa2_eth_priv *priv) +static void wait_for_fq_empty(struct dpaa2_eth_priv *priv) { - struct dpaa2_eth_channel *ch; - int i; - u32 drained = 0; - - for (i = 0; i < priv->num_channels; i++) { - ch = priv->channel[i]; - drained += drain_channel(ch); - } + int retries = 10; + u32 pending; - return drained; + do { + pending = ingress_fq_count(priv); + if (pending) + msleep(100); + } while (pending && --retries); } static int dpaa2_eth_stop(struct net_device *net_dev) @@ -1278,14 +1280,22 @@ static int dpaa2_eth_stop(struct net_device *net_dev) struct dpaa2_eth_priv *priv = netdev_priv(net_dev); int dpni_enabled = 0; int retries = 10; - u32 drained; netif_tx_stop_all_queues(net_dev); netif_carrier_off(net_dev); - /* Loop while dpni_disable() attempts to drain the egress FQs - * and confirm them back to us. + /* On dpni_disable(), the MC firmware will: + * - stop MAC Rx and wait for all Rx frames to be enqueued to software + * - cut off WRIOP dequeues from egress FQs and wait until transmission + * of all in flight Tx frames is finished (and corresponding Tx conf + * frames are enqueued back to software) + * + * Before calling dpni_disable(), we wait for all Tx frames to arrive + * on WRIOP. After it finishes, wait until all remaining frames on Rx + * and Tx conf queues are consumed on NAPI poll. */ + msleep(500); + do { dpni_disable(priv->mc_io, 0, priv->mc_token); dpni_is_enabled(priv->mc_io, 0, priv->mc_token, &dpni_enabled); @@ -1300,19 +1310,9 @@ static int dpaa2_eth_stop(struct net_device *net_dev) */ } - /* Wait for NAPI to complete on every core and disable it. - * In particular, this will also prevent NAPI from being rescheduled if - * a new CDAN is serviced, effectively discarding the CDAN. We therefore - * don't even need to disarm the channels, except perhaps for the case - * of a huge coalescing value. - */ + wait_for_fq_empty(priv); disable_ch_napi(priv); - /* Manually drain the Rx and TxConf queues */ - drained = drain_ingress_frames(priv); - if (drained) - netdev_dbg(net_dev, "Drained %d frames.\n", drained); - /* Empty the buffer pool */ drain_pool(priv); -- cgit v1.2.3 From 6394d98df6b47a4fe28715536bd6c8e003847071 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 17 Jan 2019 00:35:43 +0000 Subject: sb1000: fix a couple of indentation issues and remove assignment in if statements There is an if statement and a return statement that are incorrectly indented. Fix these. Also replace the assignment-in-if statements to assignment followed by an if to keep to the coding style. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/sb1000.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 7820fced33f6..941cfa8f1c2a 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -535,17 +535,20 @@ sb1000_activate(const int ioaddr[], const char* name) int status; ssleep(1); - if ((status = card_send_command(ioaddr, name, Command0, st))) + status = card_send_command(ioaddr, name, Command0, st); + if (status) return status; - if ((status = card_send_command(ioaddr, name, Command1, st))) + status = card_send_command(ioaddr, name, Command1, st); + if (status) return status; if (st[3] != 0xf1) { - if ((status = sb1000_start_get_set_command(ioaddr, name))) + status = sb1000_start_get_set_command(ioaddr, name); + if (status) return status; return -EIO; } udelay(1000); - return sb1000_start_get_set_command(ioaddr, name); + return sb1000_start_get_set_command(ioaddr, name); } /* get SB1000 firmware version */ -- cgit v1.2.3 From 5c423d71147422a2ba89a3cb4aaf83def2a4cec0 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 17 Jan 2019 20:59:19 +0800 Subject: net: ethernet: ti: cpsw-phy-sel: remove unneeded semicolon Remove unneeded semicolon. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw-phy-sel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c index 396e1cd10667..fec275e2208d 100644 --- a/drivers/net/ethernet/ti/cpsw-phy-sel.c +++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c @@ -78,7 +78,7 @@ static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv, case PHY_INTERFACE_MODE_MII: mode = AM33XX_GMII_SEL_MODE_MII; break; - }; + } mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6); mask |= BIT(slave + 4); @@ -133,7 +133,7 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv, case PHY_INTERFACE_MODE_MII: mode = AM33XX_GMII_SEL_MODE_MII; break; - }; + } switch (slave) { case 0: -- cgit v1.2.3 From bec03debe2e5ebc1c8bb811852b6106ce2129d71 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 17 Jan 2019 21:03:56 +0800 Subject: net/mlx4: remove unneeded semicolon Remove unneeded semicolon. Signed-off-by: YueHaibing Reviewed-by: Leon Romanovsky Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx4/eq.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index e65bc3c95630..c19e74e6ac94 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -3274,7 +3274,7 @@ int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_stat mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n", link_state, slave, port); return -EINVAL; - }; + } s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; s_info->link_state = link_state; diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 2df92dbd38e1..4953c852c247 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -820,7 +820,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? "HW" : "SW"); break; - }; + } ++eq->cons_index; eqes_found = 1; -- cgit v1.2.3 From 8eb58994dd96da7055721c68e46b732febe671ae Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 8 Jan 2019 16:45:22 +0100 Subject: usb: hub: add retry routine after intr URB submit error The hub sends hot-plug events to the host trough it's interrupt URB. The driver takes care of completing the URB and re-submitting it. Completion errors are handled in the hub_event() work, yet submission errors are ignored, rendering the device unresponsive. All further events are lost. It is fairly hard to find this issue in the wild, since you have to time the USB hot-plug event with the URB submission failure. For instance it could be the system running out of memory or some malfunction in the USB controller driver. Nevertheless, it's pretty reasonable to think it'll happen sometime. One can trigger this issue using eBPF's function override feature (see BCC's inject.py script). This patch adds a retry routine to the event of a submission error. The HUB driver will try to re-submit the URB once every second until it's successful or the HUB is disconnected. As some USB subsystems already take care of this issue, the implementation was inspired from usbhid/hid_core.c's. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Oliver Neukum Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 43 +++++++++++++++++++++++++++++++++++++------ drivers/usb/core/hub.h | 2 ++ 2 files changed, 39 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1d1e61e980f3..713ab85332f8 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -607,6 +607,36 @@ static int hub_port_status(struct usb_hub *hub, int port1, status, change, NULL); } +static void hub_resubmit_irq_urb(struct usb_hub *hub) +{ + unsigned long flags; + int status; + + spin_lock_irqsave(&hub->irq_urb_lock, flags); + + if (hub->quiescing) { + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); + return; + } + + status = usb_submit_urb(hub->urb, GFP_ATOMIC); + if (status && status != -ENODEV && status != -EPERM && + status != -ESHUTDOWN) { + dev_err(hub->intfdev, "resubmit --> %d\n", status); + mod_timer(&hub->irq_urb_retry, jiffies + HZ); + } + + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); +} + +static void hub_retry_irq_urb(struct timer_list *t) +{ + struct usb_hub *hub = from_timer(hub, t, irq_urb_retry); + + hub_resubmit_irq_urb(hub); +} + + static void kick_hub_wq(struct usb_hub *hub) { struct usb_interface *intf; @@ -709,12 +739,7 @@ static void hub_irq(struct urb *urb) kick_hub_wq(hub); resubmit: - if (hub->quiescing) - return; - - status = usb_submit_urb(hub->urb, GFP_ATOMIC); - if (status != 0 && status != -ENODEV && status != -EPERM) - dev_err(hub->intfdev, "resubmit --> %d\n", status); + hub_resubmit_irq_urb(hub); } /* USB 2.0 spec Section 11.24.2.3 */ @@ -1264,10 +1289,13 @@ enum hub_quiescing_type { static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) { struct usb_device *hdev = hub->hdev; + unsigned long flags; int i; /* hub_wq and related activity won't re-trigger */ + spin_lock_irqsave(&hub->irq_urb_lock, flags); hub->quiescing = 1; + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); if (type != HUB_SUSPEND) { /* Disconnect all the children */ @@ -1278,6 +1306,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) } /* Stop hub_wq and related activity */ + del_timer_sync(&hub->irq_urb_retry); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); @@ -1810,6 +1839,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); INIT_WORK(&hub->events, hub_event); + spin_lock_init(&hub->irq_urb_lock); + timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); usb_get_intf(intf); usb_get_dev(hdev); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 4accfb63f7dc..a9e24e4b8df1 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -69,6 +69,8 @@ struct usb_hub { struct delayed_work leds; struct delayed_work init_work; struct work_struct events; + spinlock_t irq_urb_lock; + struct timer_list irq_urb_retry; struct usb_port **ports; }; -- cgit v1.2.3 From da79ff6e586bd5aaa3bd9c73e56ae9d9183c3263 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 09:40:46 -0600 Subject: xhci: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 005e65922608..7fa58c99f126 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1455,8 +1455,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag else num_tds = 1; - urb_priv = kzalloc(sizeof(struct urb_priv) + - num_tds * sizeof(struct xhci_td), mem_flags); + urb_priv = kzalloc(struct_size(urb_priv, td, num_tds), mem_flags); if (!urb_priv) return -ENOMEM; -- cgit v1.2.3 From 6041828fdae09b973d3eed4e2c1ae82ddcf28c58 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 10:27:00 -0600 Subject: uwb: use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/uwb/drp-ie.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c index 1d2a939cfcf8..ed993e363472 100644 --- a/drivers/uwb/drp-ie.c +++ b/drivers/uwb/drp-ie.c @@ -125,9 +125,8 @@ static struct uwb_ie_drp *uwb_drp_ie_alloc(void) { struct uwb_ie_drp *drp_ie; - drp_ie = kzalloc(sizeof(struct uwb_ie_drp) + - UWB_NUM_ZONES * sizeof(struct uwb_drp_alloc), - GFP_KERNEL); + drp_ie = kzalloc(struct_size(drp_ie, allocs, UWB_NUM_ZONES), + GFP_KERNEL); if (drp_ie) drp_ie->hdr.element_id = UWB_IE_DRP; return drp_ie; -- cgit v1.2.3 From fecb28291404786b921c3f116aedb17a04fa4884 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 16 Jan 2019 10:57:43 +0100 Subject: USB: host: ohci-at91: add sam9x60-sfr definition for ohci Add this SFR compatible definition for the sam9x60 SoC and manage its use in ohci-at91.c driver. Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index ec6739ef3129..fc35a7993b7b 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -141,8 +141,11 @@ static struct regmap *at91_dt_syscon_sfr(void) struct regmap *regmap; regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); - if (IS_ERR(regmap)) - regmap = NULL; + if (IS_ERR(regmap)) { + regmap = syscon_regmap_lookup_by_compatible("microchip,sam9x60-sfr"); + if (IS_ERR(regmap)) + regmap = NULL; + } return regmap; } -- cgit v1.2.3 From bb09779f879371fcf0b8f07d932451966cd3b3f3 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 17 Jan 2019 16:24:15 +0900 Subject: usb: renesas_usbhs: replace udelay() with usleep_range() According to Documentation/timers/timers-howto.txt, a driver should use usleep_range() instead of udelay() on NON-ATOMIC CONTEXT if "SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms)". Since the .hardware_init() and .power_ctrl() will run on NON-ATOMIC CONTEXT, this patch replaces udelay() with usleep_range(). Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/rcar3.c | 2 +- drivers/usb/renesas_usbhs/rza.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index aa3820448286..5e730e9b40ef 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -59,7 +59,7 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, if (enable) { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); /* The controller on R-Car Gen3 needs to wait up to 45 usec */ - udelay(45); + usleep_range(45, 90); } else { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0); } diff --git a/drivers/usb/renesas_usbhs/rza.c b/drivers/usb/renesas_usbhs/rza.c index 5b287257ec11..8c739bd24acd 100644 --- a/drivers/usb/renesas_usbhs/rza.c +++ b/drivers/usb/renesas_usbhs/rza.c @@ -35,7 +35,7 @@ static int usbhs_rza1_hardware_init(struct platform_device *pdev) /* Enable USB PLL (NOTE: ch0 controls both ch0 and ch1) */ usbhs_bset(priv, SYSCFG, UPLLE, UPLLE); - udelay(1000); + usleep_range(1000, 2000); usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM); return 0; -- cgit v1.2.3 From 02a50b8750464fd1b9b8a80e0539fe469741b370 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Wed, 16 Jan 2019 15:20:37 +0100 Subject: usb: usb251xb: add usb data lane port swap feature The HW can swap the USB differential-pair (D+/D-) for each port separately. So the USB signals can be re-aligned with a misplaced USB connector on the PCB. Signed-off-by: Marco Felsch Reviewed-by: Richard Leitner Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usb251xb.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index a6efb9a72939..4d72b7d1d383 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -337,10 +337,12 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, struct device *dev = hub->dev; struct device_node *np = dev->of_node; int len, err, i; - u32 property_u32 = 0; + u32 port, property_u32 = 0; const u32 *cproperty_u32; const char *cproperty_char; char str[USB251XB_STRING_BUFSIZE / 2]; + struct property *prop; + const __be32 *p; if (!np) { dev_err(dev, "failed to get ofdata\n"); @@ -539,6 +541,16 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, (wchar_t *)hub->serial, USB251XB_STRING_BUFSIZE); + /* + * The datasheet documents the register as 'Port Swap' but in real the + * register controls the USB DP/DM signal swapping for each port. + */ + hub->port_swap = USB251XB_DEF_PORT_SWAP; + of_property_for_each_u32(np, "swap-dx-lanes", prop, p, port) { + if ((port >= 0) && (port <= data->port_cnt)) + hub->port_swap |= BIT(port); + } + /* The following parameters are currently not exposed to devicetree, but * may be as soon as needed. */ @@ -546,7 +558,6 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->boost_up = USB251XB_DEF_BOOST_UP; hub->boost_57 = USB251XB_DEF_BOOST_57; hub->boost_14 = USB251XB_DEF_BOOST_14; - hub->port_swap = USB251XB_DEF_PORT_SWAP; hub->port_map12 = USB251XB_DEF_PORT_MAP_12; hub->port_map34 = USB251XB_DEF_PORT_MAP_34; hub->port_map56 = USB251XB_DEF_PORT_MAP_56; -- cgit v1.2.3 From 972a34e1c7c7ebf39a76f918166e6ee3a9f0aaa2 Mon Sep 17 00:00:00 2001 From: Ran Wang Date: Thu, 17 Jan 2019 09:10:50 +0000 Subject: usb: ehci: fsl: Update register accessing for arm/arm64 platforms arm/arm64's io.h doesn't define clrbits32() and clrsetbits_be32(), which causing compile failure on some Layerscape Platforms (such as LS1021A and LS2012A which also integrates FSL EHCI controller). So use ioread32be()/iowrite32be() instead to make it workable on both powerpc and arm. Signed-off-by: Ran Wang Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 62 ++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 0a9fd2022acf..0a867d96c126 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "ehci.h" #include "ehci-fsl.h" @@ -50,6 +51,7 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) struct resource *res; int irq; int retval; + u32 tmp; pr_debug("initializing FSL-SOC USB Controller\n"); @@ -114,17 +116,22 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) } /* Enable USB controller, 83xx or 8536 */ - if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) - clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, 0x4); - + if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) { + tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= 0x4; + iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL); + } /* * Enable UTMI phy and program PTS field in UTMI mode before asserting * controller reset for USB Controller version 2.5 */ if (pdata->has_fsl_erratum_a007792) { - clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, CTRL_UTMI_PHY_EN); + tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= CTRL_UTMI_PHY_EN; + iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL); + writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1); } @@ -174,7 +181,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc; + u32 portsc, tmp; struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; struct device *dev = hcd->self.controller; @@ -192,11 +199,16 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrbits32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, - ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); + /* turn off UTMI PHY first */ + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~(CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + + /* then turn on ULPI and enable USB controller */ + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); } portsc |= PORT_PTS_ULPI; break; @@ -210,16 +222,21 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_UTMI_DUAL: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, UTMI_PHY_EN); + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= UTMI_PHY_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to become stable - 10ms*/ } /* enable UTMI PHY */ - if (pdata->have_sysif_regs) - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, - CTRL_UTMI_PHY_EN); + if (pdata->have_sysif_regs) { + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= CTRL_UTMI_PHY_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + } portsc |= PORT_PTS_UTMI; break; case FSL_USB2_PHY_NONE: @@ -241,9 +258,12 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); - if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, USB_CTRL_USB_EN); + if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) { + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= USB_CTRL_USB_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + } return 0; } -- cgit v1.2.3 From 73855109a92c72e41c424aff15c23a289dde032b Mon Sep 17 00:00:00 2001 From: Ran Wang Date: Thu, 17 Jan 2019 09:10:53 +0000 Subject: usb: kconfig: remove dependency FSL_SOC for ehci fsl driver CONFIG_USB_EHCI_FSL is not dependent on FSL_SOC, it can be built on non-PPC platforms. Signed-off-by: Rajesh Bhagat Signed-off-by: Ran Wang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 16758b12a5e9..11db5b2a30f2 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -179,8 +179,7 @@ config XPS_USB_HCD_XILINX devices only. config USB_EHCI_FSL - tristate "Support for Freescale PPC on-chip EHCI USB controller" - depends on FSL_SOC + tristate "Support for Freescale on-chip EHCI USB controller" select USB_EHCI_ROOT_HUB_TT ---help--- Variation of ARC USB block used in some Freescale chips. -- cgit v1.2.3 From 5f620bb6439ea8f354cfe4c7d47887df9d3acaf0 Mon Sep 17 00:00:00 2001 From: Ran Wang Date: Thu, 17 Jan 2019 09:10:55 +0000 Subject: drivers: usb :fsl: Remove USB Errata checking code Remove USB errata checking code from driver. Applicability of erratum is retrieved by reading corresponding property in device tree. This property is written during device tree fixup. Besides, replace spaces with tabs to make code aligned. Signed-off-by: Ramneek Mehresh Signed-off-by: Nikhil Badola Signed-off-by: Yinbo Zhu Signed-off-by: Ran Wang Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 7 +------ drivers/usb/host/fsl-mph-dr-of.c | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 0a867d96c126..e3d0c1c25160 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -304,14 +304,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) return -EINVAL; if (pdata->operating_mode == FSL_USB2_MPH_HOST) { - unsigned int chip, rev, svr; - - svr = mfspr(SPRN_SVR); - chip = svr >> 16; - rev = (svr >> 4) & 0xf; /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */ - if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055)) + if (pdata->has_fsl_erratum_14 == 1) ehci->has_fsl_port_bug = 1; if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 677f9d592109..4f8b8a08c914 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -225,6 +225,12 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->has_fsl_erratum_a005697 = of_property_read_bool(np, "fsl,usb_erratum-a005697"); + if (of_get_property(np, "fsl,usb_erratum_14", NULL)) + pdata->has_fsl_erratum_14 = 1; + else + pdata->has_fsl_erratum_14 = 0; + + /* * Determine whether phy_clk_valid needs to be checked * by reading property in device tree -- cgit v1.2.3 From 7529b2574a7aaf902f1f8159fbc2a7caa74be559 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sat, 12 Jan 2019 03:54:24 +0800 Subject: USB: Add new USB LPM helpers Use new helpers to make LPM enabling/disabling more clear. This is a preparation to subsequent patch. Signed-off-by: Kai-Heng Feng Cc: stable # after much soaking Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 12 +++++++++++- drivers/usb/core/hub.c | 12 ++++++------ drivers/usb/core/message.c | 2 +- drivers/usb/core/sysfs.c | 5 ++++- drivers/usb/core/usb.h | 10 ++++++++-- 5 files changed, 30 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 53564386ed57..c276ffc5561f 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1896,7 +1896,7 @@ int usb_runtime_idle(struct device *dev) return -EBUSY; } -int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) { struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; @@ -1913,6 +1913,16 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) return ret; } +int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + return usb_set_usb2_hardware_lpm(udev, 1); +} + +int usb_disable_usb2_hardware_lpm(struct usb_device *udev) +{ + return usb_set_usb2_hardware_lpm(udev, 0); +} + #endif /* CONFIG_PM */ struct bus_type usb_bus_type = { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 713ab85332f8..7337e942e9b0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3252,7 +3252,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) /* disable USB2 hardware LPM */ if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); if (usb_disable_ltm(udev)) { dev_err(&udev->dev, "Failed to disable LTM before suspend\n"); @@ -3291,7 +3291,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) err_ltm: /* Try to enable USB2 hardware LPM again */ if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); if (udev->do_remote_wakeup) (void) usb_disable_remote_wakeup(udev); @@ -3575,7 +3575,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) } else { /* Try to enable USB2 hardware LPM */ if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); /* Try to enable USB3 LTM */ usb_enable_ltm(udev); @@ -4466,7 +4466,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { udev->usb2_hw_lpm_allowed = 1; - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); } } @@ -5681,7 +5681,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) * It will be re-enabled by the enumeration process. */ if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); /* Disable LPM while we reset the device and reinstall the alt settings. * Device-initiated LPM, and system exit latency settings are cleared @@ -5784,7 +5784,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) done: /* Now that the alt settings are re-installed, enable LTM and LPM. */ - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); usb_release_bos_descriptor(udev); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index bfa5eda0cc26..35951aea7f50 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1244,7 +1244,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) } if (dev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(dev, 0); + usb_disable_usb2_hardware_lpm(dev); usb_unlocked_disable_lpm(dev); usb_disable_ltm(dev); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index ea18284dfa9a..7e88fdfe3cf5 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -528,7 +528,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, if (!ret) { udev->usb2_hw_lpm_allowed = value; - ret = usb_set_usb2_hardware_lpm(udev, value); + if (value) + ret = usb_enable_usb2_hardware_lpm(udev); + else + ret = usb_disable_usb2_hardware_lpm(udev); } usb_unlock_device(udev); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 546a2219454b..d95a5358f73d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -92,7 +92,8 @@ extern int usb_remote_wakeup(struct usb_device *dev); extern int usb_runtime_suspend(struct device *dev); extern int usb_runtime_resume(struct device *dev); extern int usb_runtime_idle(struct device *dev); -extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable); +extern int usb_enable_usb2_hardware_lpm(struct usb_device *udev); +extern int usb_disable_usb2_hardware_lpm(struct usb_device *udev); #else @@ -112,7 +113,12 @@ static inline int usb_autoresume_device(struct usb_device *udev) return 0; } -static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static inline int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + return 0; +} + +static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev) { return 0; } -- cgit v1.2.3 From d7a6c0ce8d26412903c7981503bad9e1cc7c45d2 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sat, 12 Jan 2019 03:54:25 +0800 Subject: USB: Consolidate LPM checks to avoid enabling LPM twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit USB Bluetooth controller QCA ROME (0cf3:e007) sometimes stops working after S3: [ 165.110742] Bluetooth: hci0: using NVM file: qca/nvm_usb_00000302.bin [ 168.432065] Bluetooth: hci0: Failed to send body at 4 of 1953 (-110) After some experiments, I found that disabling LPM can workaround the issue. On some platforms, the USB power is cut during S3, so the driver uses reset-resume to resume the device. During port resume, LPM gets enabled twice, by usb_reset_and_verify_device() and usb_port_resume(). Consolidate all checks into new LPM helpers to make sure LPM only gets enabled once. Fixes: de68bab4fa96 ("usb: Don't enable USB 2.0 Link PM by default.”) Signed-off-by: Kai-Heng Feng Cc: stable # after much soaking Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 11 ++++++++--- drivers/usb/core/hub.c | 12 ++++-------- drivers/usb/core/message.c | 3 +-- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index c276ffc5561f..8987cec9549d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1901,9 +1901,6 @@ static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; - if (enable && !udev->usb2_hw_lpm_allowed) - return 0; - if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) @@ -1915,11 +1912,19 @@ static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) int usb_enable_usb2_hardware_lpm(struct usb_device *udev) { + if (!udev->usb2_hw_lpm_capable || + !udev->usb2_hw_lpm_allowed || + udev->usb2_hw_lpm_enabled) + return 0; + return usb_set_usb2_hardware_lpm(udev, 1); } int usb_disable_usb2_hardware_lpm(struct usb_device *udev) { + if (!udev->usb2_hw_lpm_enabled) + return 0; + return usb_set_usb2_hardware_lpm(udev, 0); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7337e942e9b0..bb0830c72286 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3251,8 +3251,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) } /* disable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_disable_usb2_hardware_lpm(udev); + usb_disable_usb2_hardware_lpm(udev); if (usb_disable_ltm(udev)) { dev_err(&udev->dev, "Failed to disable LTM before suspend\n"); @@ -3290,8 +3289,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_enable_ltm(udev); err_ltm: /* Try to enable USB2 hardware LPM again */ - if (udev->usb2_hw_lpm_capable == 1) - usb_enable_usb2_hardware_lpm(udev); + usb_enable_usb2_hardware_lpm(udev); if (udev->do_remote_wakeup) (void) usb_disable_remote_wakeup(udev); @@ -3574,8 +3572,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) hub_port_logical_disconnect(hub, port1); } else { /* Try to enable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_capable == 1) - usb_enable_usb2_hardware_lpm(udev); + usb_enable_usb2_hardware_lpm(udev); /* Try to enable USB3 LTM */ usb_enable_ltm(udev); @@ -5680,8 +5677,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) /* Disable USB2 hardware LPM. * It will be re-enabled by the enumeration process. */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_disable_usb2_hardware_lpm(udev); + usb_disable_usb2_hardware_lpm(udev); /* Disable LPM while we reset the device and reinstall the alt settings. * Device-initiated LPM, and system exit latency settings are cleared diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 35951aea7f50..4f33eb632a88 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1243,8 +1243,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev->actconfig->interface[i] = NULL; } - if (dev->usb2_hw_lpm_enabled == 1) - usb_disable_usb2_hardware_lpm(dev); + usb_disable_usb2_hardware_lpm(dev); usb_unlocked_disable_lpm(dev); usb_disable_ltm(dev); -- cgit v1.2.3 From 56eec1806fac3cc585eb8644e36e8cc30bcbcbb1 Mon Sep 17 00:00:00 2001 From: Jitendra Khasdev Date: Tue, 15 Jan 2019 21:06:56 +0530 Subject: staging: comedi: Removed not necessary braces for single block This patch is used to remove not necessary braces for single if block. Signed-off-by: Jitendra Khasdev Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 5d2fcbfe02af..38980fad8be4 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1605,9 +1605,9 @@ static int do_insn_ioctl(struct comedi_device *dev, unsigned int n_data = MIN_SAMPLES; int ret = 0; - if (copy_from_user(&insn, arg, sizeof(insn))) { + if (copy_from_user(&insn, arg, sizeof(insn))) return -EFAULT; - } + n_data = max(n_data, insn.n); -- cgit v1.2.3 From 58d37ddf75a481605c9316392988a2ab87cc24b2 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Tue, 15 Jan 2019 17:36:39 +0100 Subject: staging: rtl8188eu: cleanup declarations in os_intfs.c Replace tabs with spaces and/or remove extra spaces in declarations. Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/os_intfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index 72fa446cb953..130d7261f20e 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -137,7 +137,7 @@ static int netdev_close(struct net_device *pnetdev); static void loadparam(struct adapter *padapter, struct net_device *pnetdev) { - struct registry_priv *registry_par = &padapter->registrypriv; + struct registry_priv *registry_par = &padapter->registrypriv; GlobalDebugLevel = rtw_debug; @@ -248,7 +248,7 @@ static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev, select_queue_fallback_t fallback) { - struct adapter *padapter = rtw_netdev_priv(dev); + struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; skb->priority = rtw_classify8021d(skb); @@ -263,7 +263,7 @@ u16 rtw_recv_select_queue(struct sk_buff *skb) { struct iphdr *piphdr; unsigned int dscp; - __be16 eth_type; + __be16 eth_type; u32 priority; u8 *pdata = skb->data; @@ -286,7 +286,7 @@ static const struct net_device_ops rtw_netdev_ops = { .ndo_open = netdev_open, .ndo_stop = netdev_close, .ndo_start_xmit = rtw_xmit_entry, - .ndo_select_queue = rtw_select_queue, + .ndo_select_queue = rtw_select_queue, .ndo_set_mac_address = rtw_net_set_mac_address, .ndo_get_stats = rtw_net_get_stats, .ndo_do_ioctl = rtw_ioctl, @@ -361,7 +361,7 @@ void rtw_stop_drv_threads(struct adapter *padapter) static u8 rtw_init_default_value(struct adapter *padapter) { struct registry_priv *pregistrypriv = &padapter->registrypriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv *psecuritypriv = &padapter->securitypriv; @@ -431,7 +431,7 @@ u8 rtw_reset_drv_sw(struct adapter *padapter) u8 rtw_init_drv_sw(struct adapter *padapter) { - u8 ret8 = _SUCCESS; + u8 ret8 = _SUCCESS; RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw\n")); -- cgit v1.2.3 From 9435bbd4b9d95280230bae09bad9e136941a500a Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Tue, 15 Jan 2019 17:36:40 +0100 Subject: staging: rtl8188eu: add spaces around operators in os_intfs.c Add spaces around '+', '<<' and '*' to follow kernel coding style. Reported by checkpatch. Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/os_intfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index 130d7261f20e..8dde5a40e253 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -267,11 +267,11 @@ u16 rtw_recv_select_queue(struct sk_buff *skb) u32 priority; u8 *pdata = skb->data; - memcpy(ð_type, pdata+(ETH_ALEN<<1), 2); + memcpy(ð_type, pdata + (ETH_ALEN << 1), 2); switch (eth_type) { case htons(ETH_P_IP): - piphdr = (struct iphdr *)(pdata+ETH_HLEN); + piphdr = (struct iphdr *)(pdata + ETH_HLEN); dscp = piphdr->tos & 0xfc; priority = dscp >> 5; break; @@ -323,7 +323,7 @@ struct net_device *rtw_init_netdev(struct adapter *old_padapter) padapter->pnetdev = pnetdev; DBG_88E("register rtw_netdev_ops to netdev_ops\n"); pnetdev->netdev_ops = &rtw_netdev_ops; - pnetdev->watchdog_timeo = HZ*3; /* 3 second timeout */ + pnetdev->watchdog_timeo = HZ * 3; /* 3 second timeout */ pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def; loadparam(padapter, pnetdev); -- cgit v1.2.3 From 6e3da68c7f8c645e0ea07b158ab56965bac4ea2d Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Thu, 17 Jan 2019 20:23:00 +0100 Subject: staging: rtl8188eu: add spaces around operators in mlme_linux.c Add spaces around '+' and '-' to follow kernel coding style. Reported by checkpatch. Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/mlme_linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c index d5ceb3beabbc..8180769610c3 100644 --- a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c @@ -99,13 +99,13 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) memset(buff, 0, IW_CUSTOM_MAX); p = buff; p += sprintf(p, "ASSOCINFO(ReqIEs ="); - len = sec_ie[1]+2; + len = sec_ie[1] + 2; len = min_t(uint, len, IW_CUSTOM_MAX); for (i = 0; i < len; i++) p += sprintf(p, "%02x", sec_ie[i]); p += sprintf(p, ")"); memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = p-buff; + wrqu.data.length = p - buff; wrqu.data.length = min_t(__u16, wrqu.data.length, IW_CUSTOM_MAX); wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff); kfree(buff); -- cgit v1.2.3 From 01f7e722aa9f0ba7df34ac5cdcc1c12e86792567 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Thu, 17 Jan 2019 20:23:01 +0100 Subject: staging: rtl8188eu: cleanup indenting issue in mlme_linux.c Cleanup indenting issue reported by checkpatch. CHECK: Alignment should match open parenthesis Signed-off-by: Michael Straube Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/mlme_linux.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c index 8180769610c3..2bc49d074ce4 100644 --- a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c @@ -52,9 +52,8 @@ void rtw_reset_securitypriv(struct adapter *adapter) memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv)); /* Restore the PMK information to securitypriv structure for the following connection. */ - memcpy(&adapter->securitypriv.PMKIDList[0], - &backup_pmkid[0], - sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); + memcpy(&adapter->securitypriv.PMKIDList[0], &backup_pmkid[0], + sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); adapter->securitypriv.PMKIDIndex = backup_index; adapter->securitypriv.btkip_countermeasure = backup_counter; adapter->securitypriv.btkip_countermeasure_time = backup_time; -- cgit v1.2.3 From 61c9314fdd303b99c8cd52bd64998d7296b36a3e Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 16 Jan 2019 16:59:52 +0800 Subject: staging: erofs: sunset erofs_workstation_cleanup_all There is only one user calling erofs_workstation_cleanup_all, and it is no likely that more users will use in that way in the future. Signed-off-by: Gao Xiang Reviewed-by: Chao Yu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/internal.h | 5 ----- drivers/staging/erofs/super.c | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index c3de24e7fb67..80cc09ea787d 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -283,11 +283,6 @@ extern int erofs_register_workgroup(struct super_block *sb, extern unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi, unsigned long nr_shrink, bool cleanup); -static inline void erofs_workstation_cleanup_all(struct super_block *sb) -{ - erofs_shrink_workstation(EROFS_SB(sb), ~0UL, true); -} - extern void erofs_workgroup_free_rcu(struct erofs_workgroup *grp); #ifdef EROFS_FS_HAS_MANAGED_CACHE diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c index 45c7f6ddb9f5..69e1840d3842 100644 --- a/drivers/staging/erofs/super.c +++ b/drivers/staging/erofs/super.c @@ -494,7 +494,8 @@ static void erofs_put_super(struct super_block *sb) mutex_lock(&sbi->umount_mutex); #ifdef CONFIG_EROFS_FS_ZIP - erofs_workstation_cleanup_all(sb); + /* clean up the compression space of this sb */ + erofs_shrink_workstation(EROFS_SB(sb), ~0UL, true); #endif erofs_unregister_super(sb); -- cgit v1.2.3 From d60eff4396f1f7423945f01acc274043c1370bc7 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 16 Jan 2019 16:59:53 +0800 Subject: staging: erofs: localize erofs_workgroup_get Staticize erofs_workgroup_get since no external user out of utils.c directly calls erofs_workgroup_get. Signed-off-by: Gao Xiang Reviewed-by: Chao Yu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/internal.h | 21 --------------------- drivers/staging/erofs/utils.c | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index 80cc09ea787d..967ec1a56726 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -252,28 +252,7 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp) } #endif -static inline int erofs_workgroup_get(struct erofs_workgroup *grp, int *ocnt) -{ - int o; - -repeat: - o = erofs_wait_on_workgroup_freezed(grp); - - if (unlikely(o <= 0)) - return -1; - - if (unlikely(atomic_cmpxchg(&grp->refcount, o, o + 1) != o)) - goto repeat; - - *ocnt = o; - return 0; -} - -#define __erofs_workgroup_get(grp) atomic_inc(&(grp)->refcount) -#define __erofs_workgroup_put(grp) atomic_dec(&(grp)->refcount) - extern int erofs_workgroup_put(struct erofs_workgroup *grp); - extern struct erofs_workgroup *erofs_find_workgroup( struct super_block *sb, pgoff_t index, bool *tag); diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c index aed211cd5875..d24945aab133 100644 --- a/drivers/staging/erofs/utils.c +++ b/drivers/staging/erofs/utils.c @@ -31,6 +31,25 @@ struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp) static atomic_long_t erofs_global_shrink_cnt; #ifdef CONFIG_EROFS_FS_ZIP +#define __erofs_workgroup_get(grp) atomic_inc(&(grp)->refcount) +#define __erofs_workgroup_put(grp) atomic_dec(&(grp)->refcount) + +static int erofs_workgroup_get(struct erofs_workgroup *grp, int *ocnt) +{ + int o; + +repeat: + o = erofs_wait_on_workgroup_freezed(grp); + + if (unlikely(o <= 0)) + return -1; + + if (unlikely(atomic_cmpxchg(&grp->refcount, o, o + 1) != o)) + goto repeat; + + *ocnt = o; + return 0; +} struct erofs_workgroup *erofs_find_workgroup( struct super_block *sb, pgoff_t index, bool *tag) -- cgit v1.2.3 From 4501ca36bc18ee73a3e88373ff50c22233b82324 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 16 Jan 2019 21:10:10 +0800 Subject: staging: erofs: move shrink accounting inside the function This patch moves the &erofs_global_shrink_cnt accounting from the caller to erofs_workgroup_get(). It's cleaner and it matches erofs_workgroup_put() better. No behavior change. Reviewed-by: Chao Yu Reviewed-by: Dan Carpenter Signed-off-by: Gao Xiang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/utils.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c index d24945aab133..5695efaeb43a 100644 --- a/drivers/staging/erofs/utils.c +++ b/drivers/staging/erofs/utils.c @@ -34,29 +34,29 @@ static atomic_long_t erofs_global_shrink_cnt; #define __erofs_workgroup_get(grp) atomic_inc(&(grp)->refcount) #define __erofs_workgroup_put(grp) atomic_dec(&(grp)->refcount) -static int erofs_workgroup_get(struct erofs_workgroup *grp, int *ocnt) +static int erofs_workgroup_get(struct erofs_workgroup *grp) { int o; repeat: o = erofs_wait_on_workgroup_freezed(grp); - if (unlikely(o <= 0)) return -1; if (unlikely(atomic_cmpxchg(&grp->refcount, o, o + 1) != o)) goto repeat; - *ocnt = o; + /* decrease refcount paired by erofs_workgroup_put */ + if (unlikely(o == 1)) + atomic_long_dec(&erofs_global_shrink_cnt); return 0; } -struct erofs_workgroup *erofs_find_workgroup( - struct super_block *sb, pgoff_t index, bool *tag) +struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb, + pgoff_t index, bool *tag) { struct erofs_sb_info *sbi = EROFS_SB(sb); struct erofs_workgroup *grp; - int oldcount; repeat: rcu_read_lock(); @@ -65,15 +65,12 @@ repeat: *tag = xa_pointer_tag(grp); grp = xa_untag_pointer(grp); - if (erofs_workgroup_get(grp, &oldcount)) { + if (erofs_workgroup_get(grp)) { /* prefer to relax rcu read side */ rcu_read_unlock(); goto repeat; } - /* decrease refcount added by erofs_workgroup_put */ - if (unlikely(oldcount == 1)) - atomic_long_dec(&erofs_global_shrink_cnt); DBG_BUGON(index != grp->index); } rcu_read_unlock(); -- cgit v1.2.3 From d55bc7ba6bee8950d036089a0d6cb8cb71ff2913 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 16 Jan 2019 16:59:55 +0800 Subject: staging: erofs: staticize erofs_shrink_count, erofs_shrink_scan Move erofs_shrinker_info to utils.c and therefore no need to globalize erofs_shrink_count and erofs_shrink_scan. Signed-off-by: Gao Xiang Reviewed-by: Chao Yu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/internal.h | 5 +---- drivers/staging/erofs/super.c | 6 ------ drivers/staging/erofs/utils.c | 14 ++++++++++---- 3 files changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index 967ec1a56726..304c79d253ae 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -589,10 +589,7 @@ extern struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp); extern void erofs_register_super(struct super_block *sb); extern void erofs_unregister_super(struct super_block *sb); -extern unsigned long erofs_shrink_count(struct shrinker *shrink, - struct shrink_control *sc); -extern unsigned long erofs_shrink_scan(struct shrinker *shrink, - struct shrink_control *sc); +extern struct shrinker erofs_shrinker_info; #ifndef lru_to_page #define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c index 69e1840d3842..af5140eede18 100644 --- a/drivers/staging/erofs/super.c +++ b/drivers/staging/erofs/super.c @@ -539,12 +539,6 @@ static void erofs_kill_sb(struct super_block *sb) kill_block_super(sb); } -static struct shrinker erofs_shrinker_info = { - .scan_objects = erofs_shrink_scan, - .count_objects = erofs_shrink_count, - .seeks = DEFAULT_SEEKS, -}; - static struct file_system_type erofs_fs_type = { .owner = THIS_MODULE, .name = "erofs", diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c index 5695efaeb43a..5f61f99f4c10 100644 --- a/drivers/staging/erofs/utils.c +++ b/drivers/staging/erofs/utils.c @@ -270,14 +270,14 @@ void erofs_unregister_super(struct super_block *sb) spin_unlock(&erofs_sb_list_lock); } -unsigned long erofs_shrink_count(struct shrinker *shrink, - struct shrink_control *sc) +static unsigned long erofs_shrink_count(struct shrinker *shrink, + struct shrink_control *sc) { return atomic_long_read(&erofs_global_shrink_cnt); } -unsigned long erofs_shrink_scan(struct shrinker *shrink, - struct shrink_control *sc) +static unsigned long erofs_shrink_scan(struct shrinker *shrink, + struct shrink_control *sc) { struct erofs_sb_info *sbi; struct list_head *p; @@ -333,3 +333,9 @@ unsigned long erofs_shrink_scan(struct shrinker *shrink, return freed; } +struct shrinker erofs_shrinker_info = { + .scan_objects = erofs_shrink_scan, + .count_objects = erofs_shrink_count, + .seeks = DEFAULT_SEEKS, +}; + -- cgit v1.2.3 From 2e1d66379ece5b8c81c748faab1ae5fe3487c592 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 16 Jan 2019 16:59:56 +0800 Subject: staging: erofs: drop the extern prefix for function definitions Fix all `CHECK: extern prototypes should be avoided in .h files' reported by checkpatch.pl. Signed-off-by: Gao Xiang Reviewed-by: Chao Yu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/internal.h | 47 +++++++++++++++++---------------------- drivers/staging/erofs/unzip_vle.h | 24 ++++++++++---------- 2 files changed, 33 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index 304c79d253ae..3a27c255950b 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -252,23 +252,20 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp) } #endif -extern int erofs_workgroup_put(struct erofs_workgroup *grp); -extern struct erofs_workgroup *erofs_find_workgroup( - struct super_block *sb, pgoff_t index, bool *tag); - -extern int erofs_register_workgroup(struct super_block *sb, - struct erofs_workgroup *grp, bool tag); - -extern unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi, - unsigned long nr_shrink, bool cleanup); - -extern void erofs_workgroup_free_rcu(struct erofs_workgroup *grp); +int erofs_workgroup_put(struct erofs_workgroup *grp); +struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb, + pgoff_t index, bool *tag); +int erofs_register_workgroup(struct super_block *sb, + struct erofs_workgroup *grp, bool tag); +unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi, + unsigned long nr_shrink, bool cleanup); +void erofs_workgroup_free_rcu(struct erofs_workgroup *grp); #ifdef EROFS_FS_HAS_MANAGED_CACHE -extern int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, - struct erofs_workgroup *egrp); -extern int erofs_try_to_free_cached_page(struct address_space *mapping, - struct page *page); +int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, + struct erofs_workgroup *egrp); +int erofs_try_to_free_cached_page(struct address_space *mapping, + struct page *page); #define MNGD_MAPPING(sbi) ((sbi)->managed_cache->i_mapping) #else @@ -495,8 +492,8 @@ static inline void __submit_bio(struct bio *bio, unsigned op, unsigned op_flags) #define EROFS_IO_MAX_RETRIES_NOFAIL CONFIG_EROFS_FS_IO_MAX_RETRIES #endif -extern struct page *__erofs_get_meta_page(struct super_block *sb, - erofs_blk_t blkaddr, bool prio, bool nofail); +struct page *__erofs_get_meta_page(struct super_block *sb, erofs_blk_t blkaddr, + bool prio, bool nofail); static inline struct page *erofs_get_meta_page(struct super_block *sb, erofs_blk_t blkaddr, bool prio) @@ -510,7 +507,7 @@ static inline struct page *erofs_get_meta_page_nofail(struct super_block *sb, return __erofs_get_meta_page(sb, blkaddr, prio, true); } -extern int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int); +int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int); static inline struct page * erofs_get_inline_page(struct inode *inode, @@ -530,9 +527,6 @@ static inline unsigned long erofs_inode_hash(erofs_nid_t nid) #endif } -extern struct inode *erofs_iget(struct super_block *sb, - erofs_nid_t nid, bool dir); - extern const struct inode_operations erofs_generic_iops; extern const struct inode_operations erofs_symlink_iops; extern const struct inode_operations erofs_fast_symlink_iops; @@ -547,6 +541,8 @@ static inline bool is_inode_fast_symlink(struct inode *inode) return inode->i_op == &erofs_fast_symlink_iops; } +struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool dir); + /* namei.c */ extern const struct inode_operations erofs_dir_iops; @@ -584,13 +580,12 @@ static inline void erofs_vunmap(const void *mem, unsigned int count) } /* utils.c */ -extern struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp); - -extern void erofs_register_super(struct super_block *sb); -extern void erofs_unregister_super(struct super_block *sb); - extern struct shrinker erofs_shrinker_info; +struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp); +void erofs_register_super(struct super_block *sb); +void erofs_unregister_super(struct super_block *sb); + #ifndef lru_to_page #define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) #endif diff --git a/drivers/staging/erofs/unzip_vle.h b/drivers/staging/erofs/unzip_vle.h index 5a4e1b62c0d1..9dafa8dc712c 100644 --- a/drivers/staging/erofs/unzip_vle.h +++ b/drivers/staging/erofs/unzip_vle.h @@ -212,18 +212,18 @@ static inline void z_erofs_onlinepage_endio(struct page *page) #define Z_EROFS_VLE_VMAP_GLOBAL_PAGES 2048 /* unzip_vle_lz4.c */ -extern int z_erofs_vle_plain_copy(struct page **compressed_pages, - unsigned clusterpages, struct page **pages, - unsigned nr_pages, unsigned short pageofs); - -extern int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages, - unsigned clusterpages, struct page **pages, - unsigned outlen, unsigned short pageofs, - void (*endio)(struct page *)); - -extern int z_erofs_vle_unzip_vmap(struct page **compressed_pages, - unsigned clusterpages, void *vaddr, unsigned llen, - unsigned short pageofs, bool overlapped); +int z_erofs_vle_plain_copy(struct page **compressed_pages, + unsigned int clusterpages, struct page **pages, + unsigned int nr_pages, unsigned short pageofs); +int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages, + unsigned int clusterpages, + struct page **pages, unsigned int outlen, + unsigned short pageofs, + void (*endio)(struct page *)); +int z_erofs_vle_unzip_vmap(struct page **compressed_pages, + unsigned int clusterpages, + void *vaddr, unsigned int llen, + unsigned short pageofs, bool overlapped); #endif -- cgit v1.2.3 From 92f6de4340ae7e1fa441bd1aaf38ce1efa2618b1 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:10 +0000 Subject: staging: wilc1000: make use of get_unaligned_le16/le32 to pack data Make use of get_unaligned_le16/le32 framework api's to pack data. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 15 +++------------ drivers/staging/wilc1000/wilc_wlan_cfg.c | 27 +++++++++++++-------------- 2 files changed, 16 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index c05c120fafc7..a71884287fca 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -2154,10 +2154,7 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) struct host_if_drv *hif_drv; struct wilc_vif *vif; - id = buffer[length - 4]; - id |= (buffer[length - 3] << 8); - id |= (buffer[length - 2] << 16); - id |= (buffer[length - 1] << 24); + id = get_unaligned_le32(&buffer[length - 4]); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) return; @@ -2197,10 +2194,7 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) mutex_lock(&hif_deinit_lock); - id = buffer[length - 4]; - id |= (buffer[length - 3] << 8); - id |= (buffer[length - 2] << 16); - id |= (buffer[length - 1] << 24); + id = get_unaligned_le32(&buffer[length - 4]); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) { mutex_unlock(&hif_deinit_lock); @@ -2251,10 +2245,7 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) struct host_if_drv *hif_drv; struct wilc_vif *vif; - id = buffer[length - 4]; - id |= buffer[length - 3] << 8; - id |= buffer[length - 2] << 16; - id |= buffer[length - 1] << 24; + id = get_unaligned_le32(&buffer[length - 4]); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) return; diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c index 8390766358da..67e9f93f7eaa 100644 --- a/drivers/staging/wilc1000/wilc_wlan_cfg.c +++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c @@ -168,7 +168,7 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size) while (size > 0) { i = 0; - wid = info[0] | (info[1] << 8); + wid = get_unaligned_le16(info); switch (GET_WID_TYPE(wid)) { case WID_CHAR: @@ -187,12 +187,13 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size) case WID_SHORT: do { - if (wl->cfg.hw[i].id == WID_NIL) + struct wilc_cfg_hword *hw = &wl->cfg.hw[i]; + + if (hw->id == WID_NIL) break; - if (wl->cfg.hw[i].id == wid) { - wl->cfg.hw[i].val = (info[4] | - (info[5] << 8)); + if (hw->id == wid) { + hw->val = get_unaligned_le16(&info[4]); break; } i++; @@ -202,14 +203,13 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size) case WID_INT: do { - if (wl->cfg.w[i].id == WID_NIL) + struct wilc_cfg_word *w = &wl->cfg.w[i]; + + if (w->id == WID_NIL) break; - if (wl->cfg.w[i].id == wid) { - wl->cfg.w[i].val = (info[4] | - (info[5] << 8) | - (info[6] << 16) | - (info[7] << 24)); + if (w->id == wid) { + w->val = get_unaligned_le32(&info[4]); break; } i++; @@ -244,7 +244,7 @@ static void wilc_wlan_parse_info_frame(struct wilc *wl, u8 *info) { u32 wid, len; - wid = info[0] | (info[1] << 8); + wid = get_unaligned_le16(info); len = info[2]; @@ -371,8 +371,7 @@ int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer, break; if (id == wid) { - u32 size = (wl->cfg.s[i].str[0] | - (wl->cfg.s[i].str[1] << 8)); + u16 size = get_unaligned_le16(wl->cfg.s[i].str); if (buffer_size >= size) { memcpy(buffer, &wl->cfg.s[i].str[2], -- cgit v1.2.3 From 4e90d5f3e85c538efd0ae059d5ccfdab3a388b49 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:13 +0000 Subject: staging: wilc1000: refactor wilc_wlan_set_bssid() Refactor code by making use of eth_zero_addr() to clear the mac address value in wilc_wlan_set_bssid(). Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_wlan.c | 6 +++++- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 16 +++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 721689048648..5b554c6d39a1 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -198,7 +198,11 @@ void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode) { struct wilc_vif *vif = netdev_priv(wilc_netdev); - memcpy(vif->bssid, bssid, 6); + if (bssid) + ether_addr_copy(vif->bssid, bssid); + else + eth_zero_addr(vif->bssid); + vif->mode = mode; } diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index ac47dda510e0..987e5ff0e44a 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -390,7 +390,6 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, struct wilc_vif *vif = netdev_priv(dev); struct wilc *wl = vif->wilc; struct host_if_drv *wfi_drv = priv->hif_drv; - u8 null_bssid[ETH_ALEN] = {0}; vif->connecting = false; @@ -402,8 +401,7 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, if (mac_status == WILC_MAC_STATUS_DISCONNECTED && conn_info->status == WLAN_STATUS_SUCCESS) { connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE; - wilc_wlan_set_bssid(priv->dev, null_bssid, - WILC_STATION_MODE); + wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE); if (!wfi_drv->p2p_connect) wlan_channel = INVALID_CHANNEL; @@ -445,7 +443,7 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, priv->p2p.recv_random = 0x00; priv->p2p.is_wilc_ie = false; eth_zero_addr(priv->associated_bss); - wilc_wlan_set_bssid(priv->dev, null_bssid, WILC_STATION_MODE); + wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE); if (!wfi_drv->p2p_connect) wlan_channel = INVALID_CHANNEL; @@ -720,13 +718,11 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, nw_info->ch, nw_info->join_params); if (ret) { - u8 null_bssid[ETH_ALEN] = {0}; - netdev_err(dev, "wilc_set_join_req(): Error\n"); ret = -ENOENT; if (!wfi_drv->p2p_connect) wlan_channel = INVALID_CHANNEL; - wilc_wlan_set_bssid(dev, null_bssid, WILC_STATION_MODE); + wilc_wlan_set_bssid(dev, NULL, WILC_STATION_MODE); goto out_error; } return 0; @@ -744,7 +740,6 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev, struct wilc *wilc = vif->wilc; struct host_if_drv *wfi_drv; int ret; - u8 null_bssid[ETH_ALEN] = {0}; vif->connecting = false; @@ -760,7 +755,7 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev, wfi_drv = (struct host_if_drv *)priv->hif_drv; if (!wfi_drv->p2p_connect) wlan_channel = INVALID_CHANNEL; - wilc_wlan_set_bssid(priv->dev, null_bssid, WILC_STATION_MODE); + wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE); priv->p2p.local_random = 0x01; priv->p2p.recv_random = 0x00; @@ -1805,9 +1800,8 @@ static int stop_ap(struct wiphy *wiphy, struct net_device *dev) int ret; struct wilc_priv *priv = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(priv->dev); - u8 null_bssid[ETH_ALEN] = {0}; - wilc_wlan_set_bssid(dev, null_bssid, WILC_AP_MODE); + wilc_wlan_set_bssid(dev, NULL, WILC_AP_MODE); ret = wilc_del_beacon(vif); -- cgit v1.2.3 From 8ffcedd6f4c2544fdb4b25479cb3d9dcd21e54e3 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:15 +0000 Subject: staging: wilc1000: use 'struct' to pack cfg header frame in wilc_wlan_cfg_commit() Make use of 'struct' to pack cfg header in wilc_wlan_cfg_commit() instead of byte by byte filling. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.h | 2 +- drivers/staging/wilc1000/wilc_wlan.c | 25 ++++++++++--------------- drivers/staging/wilc1000/wilc_wlan.h | 14 ++++++++++---- 3 files changed, 21 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index c6685c0c238b..a3400c14c308 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -251,7 +251,7 @@ struct wilc { struct mutex cfg_cmd_lock; struct wilc_cfg_frame cfg_frame; u32 cfg_frame_offset; - int cfg_seq_no; + u8 cfg_seq_no; u8 *rx_buffer; u32 rx_buffer_offset; diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 3c5e9e030cad..16b6c5552432 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -1092,24 +1092,19 @@ static int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type, { struct wilc *wilc = vif->wilc; struct wilc_cfg_frame *cfg = &wilc->cfg_frame; - int total_len = wilc->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE; - int seq_no = wilc->cfg_seq_no % 256; - int driver_handler = (u32)drv_handler; + int t_len = wilc->cfg_frame_offset + sizeof(struct wilc_cfg_cmd_hdr); if (type == WILC_CFG_SET) - cfg->wid_header[0] = 'W'; + cfg->hdr.cmd_type = 'W'; else - cfg->wid_header[0] = 'Q'; - cfg->wid_header[1] = seq_no; - cfg->wid_header[2] = (u8)total_len; - cfg->wid_header[3] = (u8)(total_len >> 8); - cfg->wid_header[4] = (u8)driver_handler; - cfg->wid_header[5] = (u8)(driver_handler >> 8); - cfg->wid_header[6] = (u8)(driver_handler >> 16); - cfg->wid_header[7] = (u8)(driver_handler >> 24); - wilc->cfg_seq_no = seq_no; - - if (!wilc_wlan_txq_add_cfg_pkt(vif, &cfg->wid_header[0], total_len)) + cfg->hdr.cmd_type = 'Q'; + + cfg->hdr.seq_no = wilc->cfg_seq_no % 256; + cfg->hdr.total_len = cpu_to_le16(t_len); + cfg->hdr.driver_handler = cpu_to_le32(drv_handler); + wilc->cfg_seq_no = cfg->hdr.seq_no; + + if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_len)) return -1; return 0; diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h index 27667131de1a..c8ca13b34691 100644 --- a/drivers/staging/wilc1000/wilc_wlan.h +++ b/drivers/staging/wilc1000/wilc_wlan.h @@ -14,7 +14,6 @@ * Mac eth header length * ********************************************/ -#define DRIVER_HANDLER_SIZE 4 #define MAX_MAC_HDR_LEN 26 /* QOS_MAC_HDR_LEN */ #define SUB_MSDU_HEADER_LENGTH 14 #define SNAP_HDR_LEN 8 @@ -251,14 +250,21 @@ struct wilc_hif_func { #define MAX_CFG_FRAME_SIZE 1468 +struct wilc_cfg_cmd_hdr { + u8 cmd_type; + u8 seq_no; + __le16 total_len; + __le32 driver_handler; +}; + struct wilc_cfg_frame { - u8 wid_header[8]; + struct wilc_cfg_cmd_hdr hdr; u8 frame[MAX_CFG_FRAME_SIZE]; }; struct wilc_cfg_rsp { - int type; - u32 seq_no; + u8 type; + u8 seq_no; }; struct wilc; -- cgit v1.2.3 From 6c2cfb4e87134cc7813183cf60991e981ec1a797 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:18 +0000 Subject: staging: wilc1000: remove the use of scan shadow buffer Remove scan shadow buffer, which is used to store a copy of scan results. Instead, use cfg80211 provided API's to retrieve required info. Remove the helper functions which are operating on shadow buffer, as it's not require now. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 94 ++---- drivers/staging/wilc1000/host_interface.h | 24 +- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 359 +++------------------- drivers/staging/wilc1000/wilc_wfi_netdevice.h | 3 - 4 files changed, 86 insertions(+), 394 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index a71884287fca..e7f8fabbcaae 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -210,7 +210,7 @@ static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) scan_req = &hif_drv->usr_scan_req; if (scan_req->scan_result) { - scan_req->scan_result(evt, NULL, scan_req->arg, NULL); + scan_req->scan_result(evt, NULL, scan_req->arg); scan_req->scan_result = NULL; } @@ -564,10 +564,10 @@ out: kfree(msg); } -static void host_int_fill_join_bss_param(struct join_bss_param *param, u8 *ies, - u16 *out_index, u8 *pcipher_tc, - u8 *auth_total_cnt, u32 tsf_lo, - u8 *rates_no) +static void host_int_fill_join_bss_param(struct join_bss_param *param, + const u8 *ies, u16 *out_index, + u8 *pcipher_tc, u8 *auth_total_cnt, + u32 tsf_lo, u8 *rates_no) { u8 ext_rates_no; u16 offset; @@ -700,31 +700,44 @@ static void host_int_fill_join_bss_param(struct join_bss_param *param, u8 *ies, *out_index = index; } -static void *host_int_parse_join_bss_param(struct network_info *info) +void *wilc_parse_join_bss_param(struct cfg80211_bss *bss) { struct join_bss_param *param; u16 index = 0; u8 rates_no = 0; u8 pcipher_total_cnt = 0; u8 auth_total_cnt = 0; + const u8 *tim_elm, *ssid_elm; + const struct cfg80211_bss_ies *ies = bss->ies; param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) return NULL; - param->dtim_period = info->dtim_period; - param->beacon_period = info->beacon_period; - param->cap_info = info->cap_info; - memcpy(param->bssid, info->bssid, 6); - memcpy((u8 *)param->ssid, info->ssid, info->ssid_len + 1); - param->ssid_len = info->ssid_len; + param->beacon_period = bss->beacon_interval; + param->cap_info = bss->capability; + ether_addr_copy(param->bssid, bss->bssid); + + ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); + if (ssid_elm) { + param->ssid_len = ssid_elm[1]; + if (param->ssid_len <= IEEE80211_MAX_SSID_LEN) + memcpy(param->ssid, ssid_elm + 2, param->ssid_len); + else + param->ssid_len = 0; + } + + tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); + if (tim_elm && tim_elm[1] >= 2) + param->dtim_period = tim_elm[3]; + memset(param->rsn_pcip_policy, 0xFF, 3); memset(param->rsn_auth_policy, 0xFF, 3); - while (index < info->ies_len) - host_int_fill_join_bss_param(param, info->ies, &index, + while (index < ies->len) + host_int_fill_join_bss_param(param, ies->data, &index, &pcipher_total_cnt, - &auth_total_cnt, info->tsf_lo, + &auth_total_cnt, ies->tsf, &rates_no); return (void *)param; @@ -829,57 +842,20 @@ static void handle_rcvd_ntwrk_info(struct work_struct *work) struct host_if_msg *msg = container_of(work, struct host_if_msg, work); struct wilc_vif *vif = msg->vif; struct rcvd_net_info *rcvd_info = &msg->body.net_info; - u32 i; - bool found; struct network_info *info = NULL; - void *params; - struct host_if_drv *hif_drv = vif->hif_drv; - struct user_scan_req *scan_req = &hif_drv->usr_scan_req; - - found = true; + struct user_scan_req *scan_req = &vif->hif_drv->usr_scan_req; if (!scan_req->scan_result) goto done; wilc_parse_network_info(rcvd_info->buffer, &info); - if (!info || !scan_req->scan_result) { - netdev_err(vif->ndev, "%s: info or scan result NULL\n", + if (!info) { + netdev_err(vif->ndev, "%s: info is NULL\n", __func__); goto done; } - for (i = 0; i < scan_req->ch_cnt; i++) { - if (memcmp(scan_req->net_info[i].bssid, info->bssid, 6) == 0) { - if (info->rssi <= scan_req->net_info[i].rssi) { - goto done; - } else { - scan_req->net_info[i].rssi = info->rssi; - found = false; - break; - } - } - } - - if (found) { - if (scan_req->ch_cnt < MAX_NUM_SCANNED_NETWORKS) { - scan_req->net_info[scan_req->ch_cnt].rssi = info->rssi; - - memcpy(scan_req->net_info[scan_req->ch_cnt].bssid, - info->bssid, 6); - - scan_req->ch_cnt++; - - info->new_network = true; - params = host_int_parse_join_bss_param(info); - - scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info, - scan_req->arg, params); - } - } else { - info->new_network = false; - scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info, - scan_req->arg, NULL); - } + scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info, scan_req->arg); done: kfree(rcvd_info->buffer); @@ -1150,8 +1126,7 @@ int wilc_disconnect(struct wilc_vif *vif) if (scan_req->scan_result) { del_timer(&hif_drv->scan_timer); - scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg, - NULL); + scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg); scan_req->scan_result = NULL; } @@ -2131,8 +2106,7 @@ int wilc_deinit(struct wilc_vif *vif) if (hif_drv->usr_scan_req.scan_result) { hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL, - hif_drv->usr_scan_req.arg, - NULL); + hif_drv->usr_scan_req.arg); hif_drv->usr_scan_req.scan_result = NULL; } diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 9b396a79b144..6a09a52c3459 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -19,7 +19,6 @@ enum { #define WILC_MAX_NUM_STA 9 #define MAX_NUM_SCANNED_NETWORKS 100 -#define MAX_NUM_SCANNED_NETWORKS_SHADOW 130 #define WILC_MAX_NUM_PROBED_SSID 10 #define TX_MIC_KEY_LEN 8 @@ -29,8 +28,6 @@ enum { #define WILC_ADD_STA_LENGTH 40 #define WILC_NUM_CONCURRENT_IFC 2 -#define NUM_RSSI 5 - enum { WILC_SET_CFG = 0, WILC_GET_CFG @@ -38,12 +35,6 @@ enum { #define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256 -struct rssi_history_buffer { - bool full; - u8 index; - s8 samples[NUM_RSSI]; -}; - struct network_info { s8 rssi; u16 cap_info; @@ -53,15 +44,9 @@ struct network_info { u16 beacon_period; u8 dtim_period; u8 ch; - unsigned long time_scan_cached; - unsigned long time_scan; - bool new_network; - u8 found; u32 tsf_lo; u8 *ies; u16 ies_len; - void *join_params; - struct rssi_history_buffer rssi_history; u64 tsf; }; @@ -129,11 +114,6 @@ enum cfg_param { WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3) }; -struct found_net_info { - u8 bssid[6]; - s8 rssi; -}; - enum scan_event { SCAN_EVENT_NETWORK_FOUND = 0, SCAN_EVENT_DONE = 1, @@ -148,7 +128,7 @@ enum conn_event { }; typedef void (*wilc_scan_result)(enum scan_event, struct network_info *, - void *, void *); + void *); typedef void (*wilc_connect_result)(enum conn_event, struct connect_info *, @@ -178,7 +158,6 @@ struct user_scan_req { wilc_scan_result scan_result; void *arg; u32 ch_cnt; - struct found_net_info net_info[MAX_NUM_SCANNED_NETWORKS]; }; struct user_conn_req { @@ -307,4 +286,5 @@ int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power); void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length); +void *wilc_parse_join_bss_param(struct cfg80211_bss *bss); #endif diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 987e5ff0e44a..381dfd835181 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -29,9 +29,6 @@ #define INVALID_CHANNEL 0 -#define nl80211_SCAN_RESULT_EXPIRE (3 * HZ) -#define SCAN_RESULT_EXPIRE (40 * HZ) - static const struct ieee80211_txrx_stypes wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_STATION] = { @@ -75,115 +72,8 @@ static u8 curr_channel; static u8 p2p_oui[] = {0x50, 0x6f, 0x9A, 0x09}; static u8 p2p_vendor_spec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03}; -#define AGING_TIME (9 * 1000) #define DURING_IP_TIME_OUT 15000 -static void clear_shadow_scan(struct wilc_priv *priv) -{ - int i; - - for (i = 0; i < priv->scanned_cnt; i++) { - kfree(priv->scanned_shadow[i].ies); - priv->scanned_shadow[i].ies = NULL; - - kfree(priv->scanned_shadow[i].join_params); - priv->scanned_shadow[i].join_params = NULL; - } - priv->scanned_cnt = 0; -} - -static u32 get_rssi_avg(struct network_info *network_info) -{ - u8 i; - int rssi_v = 0; - u8 num_rssi = (network_info->rssi_history.full) ? - NUM_RSSI : (network_info->rssi_history.index); - - for (i = 0; i < num_rssi; i++) - rssi_v += network_info->rssi_history.samples[i]; - - rssi_v /= num_rssi; - return rssi_v; -} - -static void refresh_scan(struct wilc_priv *priv, bool direct_scan) -{ - struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy; - int i; - - for (i = 0; i < priv->scanned_cnt; i++) { - struct network_info *network_info; - s32 freq; - struct ieee80211_channel *channel; - int rssi; - struct cfg80211_bss *bss; - - network_info = &priv->scanned_shadow[i]; - - if (!memcmp("DIRECT-", network_info->ssid, 7) && !direct_scan) - continue; - - freq = ieee80211_channel_to_frequency((s32)network_info->ch, - NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, freq); - rssi = get_rssi_avg(network_info); - bss = cfg80211_inform_bss(wiphy, - channel, - CFG80211_BSS_FTYPE_UNKNOWN, - network_info->bssid, - network_info->tsf, - network_info->cap_info, - network_info->beacon_period, - (const u8 *)network_info->ies, - (size_t)network_info->ies_len, - (s32)rssi * 100, - GFP_KERNEL); - cfg80211_put_bss(wiphy, bss); - } -} - -static void reset_shadow_found(struct wilc_priv *priv) -{ - int i; - - for (i = 0; i < priv->scanned_cnt; i++) - priv->scanned_shadow[i].found = 0; -} - -static void update_scan_time(struct wilc_priv *priv) -{ - int i; - - for (i = 0; i < priv->scanned_cnt; i++) - priv->scanned_shadow[i].time_scan = jiffies; -} - -static void remove_network_from_shadow(struct timer_list *t) -{ - struct wilc_priv *priv = from_timer(priv, t, aging_timer); - unsigned long now = jiffies; - int i, j; - - for (i = 0; i < priv->scanned_cnt; i++) { - if (!time_after(now, priv->scanned_shadow[i].time_scan + - (unsigned long)(SCAN_RESULT_EXPIRE))) - continue; - kfree(priv->scanned_shadow[i].ies); - priv->scanned_shadow[i].ies = NULL; - - kfree(priv->scanned_shadow[i].join_params); - - for (j = i; (j < priv->scanned_cnt - 1); j++) - priv->scanned_shadow[j] = priv->scanned_shadow[j + 1]; - - priv->scanned_cnt--; - } - - if (priv->scanned_cnt != 0) - mod_timer(&priv->aging_timer, - jiffies + msecs_to_jiffies(AGING_TIME)); -} - static void clear_during_ip(struct timer_list *t) { struct wilc_vif *vif = from_timer(vif, t, during_ip_timer); @@ -191,87 +81,15 @@ static void clear_during_ip(struct timer_list *t) vif->obtaining_ip = false; } -static int is_network_in_shadow(struct network_info *nw_info, - struct wilc_priv *priv) -{ - int state = -1; - int i; - - if (priv->scanned_cnt == 0) { - mod_timer(&priv->aging_timer, - jiffies + msecs_to_jiffies(AGING_TIME)); - state = -1; - } else { - for (i = 0; i < priv->scanned_cnt; i++) { - if (memcmp(priv->scanned_shadow[i].bssid, - nw_info->bssid, 6) == 0) { - state = i; - break; - } - } - } - return state; -} - -static void add_network_to_shadow(struct network_info *nw_info, - struct wilc_priv *priv, void *join_params) -{ - int ap_found = is_network_in_shadow(nw_info, priv); - u32 ap_index = 0; - u8 rssi_index = 0; - struct network_info *shadow_nw_info; - - if (priv->scanned_cnt >= MAX_NUM_SCANNED_NETWORKS_SHADOW) - return; - - if (ap_found == -1) { - ap_index = priv->scanned_cnt; - priv->scanned_cnt++; - } else { - ap_index = ap_found; - } - shadow_nw_info = &priv->scanned_shadow[ap_index]; - rssi_index = shadow_nw_info->rssi_history.index; - shadow_nw_info->rssi_history.samples[rssi_index++] = nw_info->rssi; - if (rssi_index == NUM_RSSI) { - rssi_index = 0; - shadow_nw_info->rssi_history.full = true; - } - shadow_nw_info->rssi_history.index = rssi_index; - shadow_nw_info->rssi = nw_info->rssi; - shadow_nw_info->cap_info = nw_info->cap_info; - shadow_nw_info->ssid_len = nw_info->ssid_len; - memcpy(shadow_nw_info->ssid, nw_info->ssid, nw_info->ssid_len); - memcpy(shadow_nw_info->bssid, nw_info->bssid, ETH_ALEN); - shadow_nw_info->beacon_period = nw_info->beacon_period; - shadow_nw_info->dtim_period = nw_info->dtim_period; - shadow_nw_info->ch = nw_info->ch; - shadow_nw_info->tsf = nw_info->tsf; - if (ap_found != -1) - kfree(shadow_nw_info->ies); - shadow_nw_info->ies = kmemdup(nw_info->ies, nw_info->ies_len, - GFP_KERNEL); - if (shadow_nw_info->ies) - shadow_nw_info->ies_len = nw_info->ies_len; - else - shadow_nw_info->ies_len = 0; - shadow_nw_info->time_scan = jiffies; - shadow_nw_info->time_scan_cached = jiffies; - shadow_nw_info->found = 1; - if (ap_found != -1) - kfree(shadow_nw_info->join_params); - shadow_nw_info->join_params = join_params; -} - static void cfg_scan_result(enum scan_event scan_event, struct network_info *network_info, - void *user_void, void *join_params) + void *user_void) { struct wilc_priv *priv; struct wiphy *wiphy; s32 freq; struct ieee80211_channel *channel; - struct cfg80211_bss *bss = NULL; + struct cfg80211_bss *bss; priv = user_void; if (!priv->cfg_scanning) @@ -291,51 +109,22 @@ static void cfg_scan_result(enum scan_event scan_event, freq = ieee80211_channel_to_frequency((s32)network_info->ch, NL80211_BAND_2GHZ); channel = ieee80211_get_channel(wiphy, freq); - if (!channel) return; - if (network_info->new_network) { - if (priv->rcvd_ch_cnt >= MAX_NUM_SCANNED_NETWORKS) - return; - - priv->rcvd_ch_cnt++; - - add_network_to_shadow(network_info, priv, join_params); - - if (memcmp("DIRECT-", network_info->ssid, 7)) - return; - - bss = cfg80211_inform_bss(wiphy, - channel, - CFG80211_BSS_FTYPE_UNKNOWN, - network_info->bssid, - network_info->tsf, - network_info->cap_info, - network_info->beacon_period, - (const u8 *)network_info->ies, - (size_t)network_info->ies_len, - (s32)network_info->rssi * 100, - GFP_KERNEL); - cfg80211_put_bss(wiphy, bss); - } else { - u32 i; - - for (i = 0; i < priv->rcvd_ch_cnt; i++) { - if (memcmp(priv->scanned_shadow[i].bssid, - network_info->bssid, 6) == 0) - break; - } - - if (i >= priv->rcvd_ch_cnt) - return; - - priv->scanned_shadow[i].rssi = network_info->rssi; - priv->scanned_shadow[i].time_scan = jiffies; - } + bss = cfg80211_inform_bss(wiphy, + channel, + CFG80211_BSS_FTYPE_UNKNOWN, + network_info->bssid, + network_info->tsf, + network_info->cap_info, + network_info->beacon_period, + (const u8 *)network_info->ies, + (size_t)network_info->ies_len, + (s32)network_info->rssi * 100, + GFP_KERNEL); + cfg80211_put_bss(wiphy, bss); } else if (scan_event == SCAN_EVENT_DONE) { - refresh_scan(priv, false); - mutex_lock(&priv->scan_req_lock); if (priv->scan_req) { @@ -344,7 +133,6 @@ static void cfg_scan_result(enum scan_event scan_event, }; cfg80211_scan_done(priv->scan_req, &info); - priv->rcvd_ch_cnt = 0; priv->cfg_scanning = false; priv->scan_req = NULL; } @@ -357,9 +145,6 @@ static void cfg_scan_result(enum scan_event scan_event, .aborted = false, }; - update_scan_time(priv); - refresh_scan(priv, false); - cfg80211_scan_done(priv->scan_req, &info); priv->cfg_scanning = false; priv->scan_req = NULL; @@ -368,17 +153,6 @@ static void cfg_scan_result(enum scan_event scan_event, } } -static inline bool wilc_cfg_scan_time_expired(struct wilc_priv *priv, int i) -{ - unsigned long now = jiffies; - - if (time_after(now, priv->scanned_shadow[i].time_scan_cached + - (unsigned long)(nl80211_SCAN_RESULT_EXPIRE - (1 * HZ)))) - return true; - else - return false; -} - static void cfg_connect_result(enum conn_event conn_disconn_evt, struct connect_info *conn_info, u8 mac_status, @@ -409,28 +183,10 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, netdev_err(dev, "Unspecified failure\n"); } - if (connect_status == WLAN_STATUS_SUCCESS) { - bool scan_refresh = false; - u32 i; - + if (connect_status == WLAN_STATUS_SUCCESS) memcpy(priv->associated_bss, conn_info->bssid, ETH_ALEN); - for (i = 0; i < priv->scanned_cnt; i++) { - if (memcmp(priv->scanned_shadow[i].bssid, - conn_info->bssid, - ETH_ALEN) == 0) { - if (wilc_cfg_scan_time_expired(priv, i)) - scan_refresh = true; - - break; - } - } - - if (scan_refresh) - refresh_scan(priv, true); - } - cfg80211_connect_result(dev, conn_info->bssid, conn_info->req_ies, conn_info->req_ies_len, @@ -531,10 +287,6 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) priv->scan_req = request; - priv->rcvd_ch_cnt = 0; - - reset_shadow_found(priv); - priv->cfg_scanning = true; if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) { for (i = 0; i < request->n_channels; i++) { @@ -583,13 +335,13 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, struct wilc_priv *priv = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(priv->dev); struct host_if_drv *wfi_drv = priv->hif_drv; - struct network_info *nw_info; int ret; u32 i; - u32 sel_bssi_idx = UINT_MAX; u8 security = WILC_FW_SEC_NO; enum authtype auth_type = WILC_FW_AUTH_ANY; u32 cipher_group; + struct cfg80211_bss *bss; + void *join_params; vif->connecting = true; @@ -598,39 +350,6 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, else wfi_drv->p2p_connect = 0; - for (i = 0; i < priv->scanned_cnt; i++) { - if (sme->ssid_len == priv->scanned_shadow[i].ssid_len && - memcmp(priv->scanned_shadow[i].ssid, - sme->ssid, - sme->ssid_len) == 0) { - if (!sme->bssid) { - if (sel_bssi_idx == UINT_MAX || - priv->scanned_shadow[i].rssi > - priv->scanned_shadow[sel_bssi_idx].rssi) - sel_bssi_idx = i; - } else { - if (memcmp(priv->scanned_shadow[i].bssid, - sme->bssid, - ETH_ALEN) == 0) { - sel_bssi_idx = i; - break; - } - } - } - } - - if (sel_bssi_idx < priv->scanned_cnt) { - nw_info = &priv->scanned_shadow[sel_bssi_idx]; - } else { - ret = -ENOENT; - goto out_error; - } - - if (ether_addr_equal_unaligned(vif->bssid, nw_info->bssid)) { - ret = -EALREADY; - goto out_error; - } - memset(priv->wep_key, 0, sizeof(priv->wep_key)); memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); @@ -704,29 +423,54 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, auth_type = WILC_FW_AUTH_IEEE8021; } - curr_channel = nw_info->ch; + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, + sme->ssid_len, IEEE80211_BSS_TYPE_ANY, + IEEE80211_PRIVACY(sme->privacy)); + if (!bss) { + ret = -EINVAL; + goto out_error; + } + + if (ether_addr_equal_unaligned(vif->bssid, bss->bssid)) { + ret = -EALREADY; + goto out_put_bss; + } + + join_params = wilc_parse_join_bss_param(bss); + if (!join_params) { + netdev_err(dev, "%s: failed to construct join param\n", + __func__); + ret = -EINVAL; + goto out_put_bss; + } + + curr_channel = ieee80211_frequency_to_channel(bss->channel->center_freq); if (!wfi_drv->p2p_connect) - wlan_channel = nw_info->ch; + wlan_channel = curr_channel; - wilc_wlan_set_bssid(dev, nw_info->bssid, WILC_STATION_MODE); + wilc_wlan_set_bssid(dev, bss->bssid, WILC_STATION_MODE); - ret = wilc_set_join_req(vif, nw_info->bssid, sme->ssid, + ret = wilc_set_join_req(vif, bss->bssid, sme->ssid, sme->ssid_len, sme->ie, sme->ie_len, cfg_connect_result, (void *)priv, - security, auth_type, - nw_info->ch, - nw_info->join_params); + security, auth_type, curr_channel, join_params); if (ret) { netdev_err(dev, "wilc_set_join_req(): Error\n"); ret = -ENOENT; if (!wfi_drv->p2p_connect) wlan_channel = INVALID_CHANNEL; wilc_wlan_set_bssid(dev, NULL, WILC_STATION_MODE); - goto out_error; + kfree(join_params); + goto out_put_bss; } + kfree(join_params); + cfg80211_put_bss(wiphy, bss); return 0; +out_put_bss: + cfg80211_put_bss(wiphy, bss); + out_error: vif->connecting = false; return ret; @@ -2096,7 +1840,6 @@ int wilc_init_host_int(struct net_device *net) struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr); struct wilc_vif *vif = netdev_priv(priv->dev); - timer_setup(&priv->aging_timer, remove_network_from_shadow, 0); timer_setup(&vif->during_ip_timer, clear_during_ip, 0); priv->p2p_listen_state = false; @@ -2120,8 +1863,6 @@ void wilc_deinit_host_int(struct net_device *net) mutex_destroy(&priv->scan_req_lock); ret = wilc_deinit(vif); - del_timer_sync(&priv->aging_timer); - clear_shadow_scan(priv); del_timer_sync(&vif->during_ip_timer); if (ret) diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index a3400c14c308..59e835259a83 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -137,7 +137,6 @@ struct wilc_priv { u64 tx_cookie; bool cfg_scanning; - u32 rcvd_ch_cnt; u8 associated_bss[ETH_ALEN]; struct sta_info assoc_stainfo; @@ -155,8 +154,6 @@ struct wilc_priv { /* mutexes */ struct mutex scan_req_lock; bool p2p_listen_state; - struct timer_list aging_timer; - struct network_info scanned_shadow[MAX_NUM_SCANNED_NETWORKS_SHADOW]; int scanned_cnt; struct wilc_p2p_var p2p; -- cgit v1.2.3 From 6cd4fa5ab6913ab8a9a35970b8c70e759c3e68cf Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:21 +0000 Subject: staging: wilc1000: make use of cfg80211_inform_bss_frame() Use cfg80211_inform_bss_frame() api instead of cfg80211_inform_bss() to inform cfg80211 about the BSS frame, to avoid unnecessary parsing of frame in driver. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 144 +++++----------------- drivers/staging/wilc1000/host_interface.h | 14 ++- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 42 +++---- 3 files changed, 50 insertions(+), 150 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index e7f8fabbcaae..68f58d11ec52 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -72,7 +72,7 @@ struct wilc_gtk_key { } __packed; union message_body { - struct rcvd_net_info net_info; + struct wilc_rcvd_net_info net_info; struct rcvd_async_info async_info; struct set_multicast multicast_info; struct remain_ch remain_on_ch; @@ -743,129 +743,38 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss) return (void *)param; } -static inline u8 *get_bssid(struct ieee80211_mgmt *mgmt) -{ - if (ieee80211_has_fromds(mgmt->frame_control)) - return mgmt->sa; - else if (ieee80211_has_tods(mgmt->frame_control)) - return mgmt->da; - else - return mgmt->bssid; -} - -static s32 wilc_parse_network_info(u8 *msg_buffer, - struct network_info **ret_network_info) +static void handle_rcvd_ntwrk_info(struct work_struct *work) { - struct network_info *info; - struct ieee80211_mgmt *mgt; - u8 *wid_val, *ies; - u16 wid_len, rx_len, ies_len; - u8 msg_type; + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info; + struct user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req; + const u8 *ch_elm; + u8 *ies; + int ies_len; size_t offset; - const u8 *ch_elm, *tim_elm, *ssid_elm; - - msg_type = msg_buffer[0]; - if ('N' != msg_type) - return -EFAULT; - - wid_len = get_unaligned_le16(&msg_buffer[6]); - wid_val = &msg_buffer[8]; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - info->rssi = wid_val[0]; - - mgt = (struct ieee80211_mgmt *)&wid_val[1]; - rx_len = wid_len - 1; - - if (ieee80211_is_probe_resp(mgt->frame_control)) { - info->cap_info = le16_to_cpu(mgt->u.probe_resp.capab_info); - info->beacon_period = le16_to_cpu(mgt->u.probe_resp.beacon_int); - info->tsf = le64_to_cpu(mgt->u.probe_resp.timestamp); - info->tsf_lo = (u32)info->tsf; + if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control)) offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - } else if (ieee80211_is_beacon(mgt->frame_control)) { - info->cap_info = le16_to_cpu(mgt->u.beacon.capab_info); - info->beacon_period = le16_to_cpu(mgt->u.beacon.beacon_int); - info->tsf = le64_to_cpu(mgt->u.beacon.timestamp); - info->tsf_lo = (u32)info->tsf; + else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control)) offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); - } else { - /* only process probe response and beacon frame */ - kfree(info); - return -EIO; - } - - ether_addr_copy(info->bssid, get_bssid(mgt)); - - ies = mgt->u.beacon.variable; - ies_len = rx_len - offset; - if (ies_len <= 0) { - kfree(info); - return -EIO; - } - - info->ies = kmemdup(ies, ies_len, GFP_KERNEL); - if (!info->ies) { - kfree(info); - return -ENOMEM; - } - - info->ies_len = ies_len; + else + goto done; - ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len); - if (ssid_elm) { - info->ssid_len = ssid_elm[1]; - if (info->ssid_len <= IEEE80211_MAX_SSID_LEN) - memcpy(info->ssid, ssid_elm + 2, info->ssid_len); - else - info->ssid_len = 0; - } + ies = rcvd_info->mgmt->u.beacon.variable; + ies_len = rcvd_info->frame_len - offset; + if (ies_len <= 0) + goto done; ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len); if (ch_elm && ch_elm[1] > 0) - info->ch = ch_elm[2]; - - tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len); - if (tim_elm && tim_elm[1] >= 2) - info->dtim_period = tim_elm[3]; - - *ret_network_info = info; - - return 0; -} - -static void handle_rcvd_ntwrk_info(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_vif *vif = msg->vif; - struct rcvd_net_info *rcvd_info = &msg->body.net_info; - struct network_info *info = NULL; - struct user_scan_req *scan_req = &vif->hif_drv->usr_scan_req; - - if (!scan_req->scan_result) - goto done; + rcvd_info->ch = ch_elm[2]; - wilc_parse_network_info(rcvd_info->buffer, &info); - if (!info) { - netdev_err(vif->ndev, "%s: info is NULL\n", - __func__); - goto done; - } - - scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info, scan_req->arg); + if (scan_req->scan_result) + scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info, + scan_req->arg); done: - kfree(rcvd_info->buffer); - rcvd_info->buffer = NULL; - - if (info) { - kfree(info->ies); - kfree(info); - } - + kfree(rcvd_info->mgmt); kfree(msg); } @@ -2143,9 +2052,12 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) if (IS_ERR(msg)) return; - msg->body.net_info.len = length; - msg->body.net_info.buffer = kmemdup(buffer, length, GFP_KERNEL); - if (!msg->body.net_info.buffer) { + msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1; + msg->body.net_info.rssi = buffer[8]; + msg->body.net_info.mgmt = kmemdup(&buffer[9], + msg->body.net_info.frame_len, + GFP_KERNEL); + if (!msg->body.net_info.mgmt) { kfree(msg); return; } @@ -2153,7 +2065,7 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) result = wilc_enqueue_work(msg); if (result) { netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); - kfree(msg->body.net_info.buffer); + kfree(msg->body.net_info.mgmt); kfree(msg); } } diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 6a09a52c3459..76da17267e24 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -127,7 +127,14 @@ enum conn_event { CONN_DISCONN_EVENT_FORCE_32BIT = 0xFFFFFFFF }; -typedef void (*wilc_scan_result)(enum scan_event, struct network_info *, +struct wilc_rcvd_net_info { + s8 rssi; + u8 ch; + u16 frame_len; + struct ieee80211_mgmt *mgmt; +}; + +typedef void (*wilc_scan_result)(enum scan_event, struct wilc_rcvd_net_info *, void *); typedef void (*wilc_connect_result)(enum conn_event, @@ -139,11 +146,6 @@ typedef void (*wilc_connect_result)(enum conn_event, typedef void (*wilc_remain_on_chan_expired)(void *, u32); typedef void (*wilc_remain_on_chan_ready)(void *); -struct rcvd_net_info { - u8 *buffer; - u32 len; -}; - struct hidden_net_info { u8 *ssid; u8 ssid_len; diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 381dfd835181..5da03bb88ab4 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -82,48 +82,34 @@ static void clear_during_ip(struct timer_list *t) } static void cfg_scan_result(enum scan_event scan_event, - struct network_info *network_info, - void *user_void) + struct wilc_rcvd_net_info *info, void *user_void) { - struct wilc_priv *priv; - struct wiphy *wiphy; - s32 freq; - struct ieee80211_channel *channel; - struct cfg80211_bss *bss; + struct wilc_priv *priv = user_void; - priv = user_void; if (!priv->cfg_scanning) return; if (scan_event == SCAN_EVENT_NETWORK_FOUND) { - wiphy = priv->dev->ieee80211_ptr->wiphy; - - if (!wiphy || !network_info) - return; + s32 freq; + struct ieee80211_channel *channel; + struct cfg80211_bss *bss; + struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy; - if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && - (((s32)network_info->rssi * 100) < 0 || - ((s32)network_info->rssi * 100) > 100)) + if (!wiphy || !info) return; - freq = ieee80211_channel_to_frequency((s32)network_info->ch, + freq = ieee80211_channel_to_frequency((s32)info->ch, NL80211_BAND_2GHZ); channel = ieee80211_get_channel(wiphy, freq); if (!channel) return; - bss = cfg80211_inform_bss(wiphy, - channel, - CFG80211_BSS_FTYPE_UNKNOWN, - network_info->bssid, - network_info->tsf, - network_info->cap_info, - network_info->beacon_period, - (const u8 *)network_info->ies, - (size_t)network_info->ies_len, - (s32)network_info->rssi * 100, - GFP_KERNEL); - cfg80211_put_bss(wiphy, bss); + bss = cfg80211_inform_bss_frame(wiphy, channel, info->mgmt, + info->frame_len, + (s32)info->rssi * 100, + GFP_KERNEL); + if (!bss) + cfg80211_put_bss(wiphy, bss); } else if (scan_event == SCAN_EVENT_DONE) { mutex_lock(&priv->scan_req_lock); -- cgit v1.2.3 From dc18fa1de9acc57d599c50437fc04a5a08e19b82 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:24 +0000 Subject: staging: wilc1000: corrected order to pack join param buffer Modified packing order for join param as expected by firmware. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 68f58d11ec52..2fb56975ccc3 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -11,8 +11,6 @@ #define FALSE_FRMWR_CHANNEL 100 -#define REAL_JOIN_REQ 0 - struct rcvd_async_info { u8 *buffer; u32 len; @@ -436,15 +434,14 @@ static int wilc_send_connect_wid(struct wilc_vif *vif) memcpy(cur_byte, bss_param->rsn_cap, sizeof(bss_param->rsn_cap)); cur_byte += sizeof(bss_param->rsn_cap); - *(cur_byte++) = REAL_JOIN_REQ; *(cur_byte++) = bss_param->noa_enabled; if (bss_param->noa_enabled) { put_unaligned_le32(bss_param->tsf, cur_byte); cur_byte += 4; - *(cur_byte++) = bss_param->opp_enabled; *(cur_byte++) = bss_param->idx; + *(cur_byte++) = bss_param->opp_enabled; if (bss_param->opp_enabled) *(cur_byte++) = bss_param->ct_window; -- cgit v1.2.3 From 4e0b0f42c9c7cbb756aee9e418f7ad15cdf16cd6 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:27 +0000 Subject: staging: wilc1000: use struct to pack join parameters for FW Refactor code to use struct to construct the join parameters. Avoid use of extra buffer before sending to FW instead directly pass the struct pointer. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 404 ++++++++-------------- drivers/staging/wilc1000/host_interface.h | 18 +- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 2 +- drivers/staging/wilc1000/wilc_wlan_if.h | 1 - 4 files changed, 142 insertions(+), 283 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 2fb56975ccc3..46fd448ddde7 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -86,34 +86,50 @@ struct host_if_msg { bool is_sync; }; -struct join_bss_param { - enum bss_types bss_type; +struct wilc_noa_opp_enable { + u8 ct_window; + u8 cnt; + __le32 duration; + __le32 interval; + __le32 start_time; +} __packed; + +struct wilc_noa_opp_disable { + u8 cnt; + __le32 duration; + __le32 interval; + __le32 start_time; +} __packed; + +struct wilc_join_bss_param { + char ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_terminator; + u8 bss_type; + u8 ch; + __le16 cap_info; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 beacon_period; u8 dtim_period; - u16 beacon_period; - u16 cap_info; - u8 bssid[6]; - char ssid[MAX_SSID_LEN]; - u8 ssid_len; u8 supp_rates[MAX_RATES_SUPPORTED + 1]; - u8 ht_capable; u8 wmm_cap; u8 uapsd_cap; - bool rsn_found; + u8 ht_capable; + u8 rsn_found; u8 rsn_grp_policy; u8 mode_802_11i; - u8 rsn_pcip_policy[3]; - u8 rsn_auth_policy[3]; + u8 p_suites[3]; + u8 akm_suites[3]; u8 rsn_cap[2]; - u32 tsf; u8 noa_enabled; - u8 opp_enabled; - u8 ct_window; - u8 cnt; + __le32 tsf_lo; u8 idx; - u8 duration[4]; - u8 interval[4]; - u8 start_time[4]; -}; + u8 opp_enabled; + union { + struct wilc_noa_opp_disable opp_dis; + struct wilc_noa_opp_enable opp_en; + }; +} __packed; static struct host_if_drv *terminated_handle; static struct mutex hif_deinit_lock; @@ -329,10 +345,9 @@ static int wilc_send_connect_wid(struct wilc_vif *vif) int result = 0; struct wid wid_list[8]; u32 wid_cnt = 0, dummyval = 0; - u8 *cur_byte = NULL; struct host_if_drv *hif_drv = vif->hif_drv; struct user_conn_req *conn_attr = &hif_drv->usr_conn_req; - struct join_bss_param *bss_param = hif_drv->usr_conn_req.param; + struct wilc_join_bss_param *bss_param = hif_drv->usr_conn_req.param; wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT; wid_list[wid_cnt].type = WID_INT; @@ -372,96 +387,8 @@ static int wilc_send_connect_wid(struct wilc_vif *vif) wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED; wid_list[wid_cnt].type = WID_STR; - wid_list[wid_cnt].size = 112; - wid_list[wid_cnt].val = kmalloc(wid_list[wid_cnt].size, GFP_KERNEL); - - if (!wid_list[wid_cnt].val) { - result = -EFAULT; - goto error; - } - - cur_byte = wid_list[wid_cnt].val; - - if (conn_attr->ssid) { - memcpy(cur_byte, conn_attr->ssid, conn_attr->ssid_len); - cur_byte[conn_attr->ssid_len] = '\0'; - } - cur_byte += MAX_SSID_LEN; - *(cur_byte++) = WILC_FW_BSS_TYPE_INFRA; - - if (conn_attr->ch >= 1 && conn_attr->ch <= 14) { - *(cur_byte++) = conn_attr->ch; - } else { - netdev_err(vif->ndev, "Channel out of range\n"); - *(cur_byte++) = 0xFF; - } - put_unaligned_le16(bss_param->cap_info, cur_byte); - cur_byte += 2; - - if (conn_attr->bssid) - memcpy(cur_byte, conn_attr->bssid, 6); - cur_byte += 6; - - if (conn_attr->bssid) - memcpy(cur_byte, conn_attr->bssid, 6); - cur_byte += 6; - - put_unaligned_le16(bss_param->beacon_period, cur_byte); - cur_byte += 2; - *(cur_byte++) = bss_param->dtim_period; - - memcpy(cur_byte, bss_param->supp_rates, MAX_RATES_SUPPORTED + 1); - cur_byte += (MAX_RATES_SUPPORTED + 1); - - *(cur_byte++) = bss_param->wmm_cap; - *(cur_byte++) = bss_param->uapsd_cap; - - *(cur_byte++) = bss_param->ht_capable; - conn_attr->ht_capable = bss_param->ht_capable; - - *(cur_byte++) = bss_param->rsn_found; - *(cur_byte++) = bss_param->rsn_grp_policy; - *(cur_byte++) = bss_param->mode_802_11i; - - memcpy(cur_byte, bss_param->rsn_pcip_policy, - sizeof(bss_param->rsn_pcip_policy)); - cur_byte += sizeof(bss_param->rsn_pcip_policy); - - memcpy(cur_byte, bss_param->rsn_auth_policy, - sizeof(bss_param->rsn_auth_policy)); - cur_byte += sizeof(bss_param->rsn_auth_policy); - - memcpy(cur_byte, bss_param->rsn_cap, sizeof(bss_param->rsn_cap)); - cur_byte += sizeof(bss_param->rsn_cap); - - *(cur_byte++) = bss_param->noa_enabled; - - if (bss_param->noa_enabled) { - put_unaligned_le32(bss_param->tsf, cur_byte); - cur_byte += 4; - - *(cur_byte++) = bss_param->idx; - *(cur_byte++) = bss_param->opp_enabled; - - if (bss_param->opp_enabled) - *(cur_byte++) = bss_param->ct_window; - - *(cur_byte++) = bss_param->cnt; - - memcpy(cur_byte, bss_param->duration, - sizeof(bss_param->duration)); - cur_byte += sizeof(bss_param->duration); - - memcpy(cur_byte, bss_param->interval, - sizeof(bss_param->interval)); - cur_byte += sizeof(bss_param->interval); - - memcpy(cur_byte, bss_param->start_time, - sizeof(bss_param->start_time)); - cur_byte += sizeof(bss_param->start_time); - } - - cur_byte = wid_list[wid_cnt].val; + wid_list[wid_cnt].size = sizeof(*bss_param); + wid_list[wid_cnt].val = (u8 *)bss_param; wid_cnt++; result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, @@ -469,13 +396,11 @@ static int wilc_send_connect_wid(struct wilc_vif *vif) wilc_get_vif_idx(vif)); if (result) { netdev_err(vif->ndev, "failed to send config packet\n"); - kfree(cur_byte); goto error; } else { hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP; } - kfree(cur_byte); return 0; error: @@ -561,181 +486,130 @@ out: kfree(msg); } -static void host_int_fill_join_bss_param(struct join_bss_param *param, - const u8 *ies, u16 *out_index, - u8 *pcipher_tc, u8 *auth_total_cnt, - u32 tsf_lo, u8 *rates_no) +void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto) { - u8 ext_rates_no; - u16 offset; - u8 pcipher_cnt; - u8 auth_cnt; - u8 i, j; - u16 index = *out_index; - - if (ies[index] == WLAN_EID_SUPP_RATES) { - *rates_no = ies[index + 1]; - param->supp_rates[0] = *rates_no; - index += 2; + struct wilc_join_bss_param *param; + struct ieee80211_p2p_noa_attr noa_attr; + u8 rates_len = 0; + const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; + const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; + int ret; + const struct cfg80211_bss_ies *ies = bss->ies; - for (i = 0; i < *rates_no; i++) - param->supp_rates[i + 1] = ies[index + i]; + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + return NULL; - index += *rates_no; - } else if (ies[index] == WLAN_EID_EXT_SUPP_RATES) { - ext_rates_no = ies[index + 1]; - if (ext_rates_no > (MAX_RATES_SUPPORTED - *rates_no)) - param->supp_rates[0] = MAX_RATES_SUPPORTED; - else - param->supp_rates[0] += ext_rates_no; - index += 2; - for (i = 0; i < (param->supp_rates[0] - *rates_no); i++) - param->supp_rates[*rates_no + i + 1] = ies[index + i]; + param->beacon_period = bss->beacon_interval; + param->cap_info = bss->capability; + param->bss_type = WILC_FW_BSS_TYPE_INFRA; + param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq); + ether_addr_copy(param->bssid, bss->bssid); - index += ext_rates_no; - } else if (ies[index] == WLAN_EID_HT_CAPABILITY) { - param->ht_capable = true; - index += ies[index + 1] + 2; - } else if ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) && - (ies[index + 2] == 0x00) && (ies[index + 3] == 0x50) && - (ies[index + 4] == 0xF2) && (ies[index + 5] == 0x02) && - ((ies[index + 6] == 0x00) || (ies[index + 6] == 0x01)) && - (ies[index + 7] == 0x01)) { - param->wmm_cap = true; - - if (ies[index + 8] & BIT(7)) - param->uapsd_cap = true; - index += ies[index + 1] + 2; - } else if ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) && - (ies[index + 2] == 0x50) && (ies[index + 3] == 0x6f) && - (ies[index + 4] == 0x9a) && - (ies[index + 5] == 0x09) && (ies[index + 6] == 0x0c)) { - u16 p2p_cnt; - - param->tsf = tsf_lo; - param->noa_enabled = 1; - param->idx = ies[index + 9]; + ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); + if (ssid_elm) { + if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN) + memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]); + } - if (ies[index + 10] & BIT(7)) { - param->opp_enabled = 1; - param->ct_window = ies[index + 10]; - } else { - param->opp_enabled = 0; - } + tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); + if (tim_elm && tim_elm[1] >= 2) + param->dtim_period = tim_elm[3]; - param->cnt = ies[index + 11]; - p2p_cnt = index + 12; + memset(param->p_suites, 0xFF, 3); + memset(param->akm_suites, 0xFF, 3); - memcpy(param->duration, ies + p2p_cnt, 4); - p2p_cnt += 4; + rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); + if (rates_ie) { + rates_len = rates_ie[1]; + param->supp_rates[0] = rates_len; + memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len); + } - memcpy(param->interval, ies + p2p_cnt, 4); - p2p_cnt += 4; + supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data, + ies->len); + if (supp_rates_ie) { + if (supp_rates_ie[1] > (MAX_RATES_SUPPORTED - rates_len)) + param->supp_rates[0] = MAX_RATES_SUPPORTED; + else + param->supp_rates[0] += supp_rates_ie[1]; - memcpy(param->start_time, ies + p2p_cnt, 4); + memcpy(¶m->supp_rates[rates_len + 1], supp_rates_ie + 2, + (param->supp_rates[0] - rates_len)); + } - index += ies[index + 1] + 2; - } else if ((ies[index] == WLAN_EID_RSN) || - ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) && - (ies[index + 2] == 0x00) && - (ies[index + 3] == 0x50) && (ies[index + 4] == 0xF2) && - (ies[index + 5] == 0x01))) { - u16 rsn_idx = index; + ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len); + if (ht_ie) + param->ht_capable = true; - if (ies[rsn_idx] == WLAN_EID_RSN) { - param->mode_802_11i = 2; + ret = cfg80211_get_p2p_attr(ies->data, ies->len, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + (u8 *)&noa_attr, sizeof(noa_attr)); + if (ret > 0) { + param->tsf_lo = cpu_to_le32(ies->tsf); + param->noa_enabled = 1; + param->idx = noa_attr.index; + if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) { + param->opp_enabled = 1; + param->opp_en.ct_window = noa_attr.oppps_ctwindow; + param->opp_en.cnt = noa_attr.desc[0].count; + param->opp_en.duration = noa_attr.desc[0].duration; + param->opp_en.interval = noa_attr.desc[0].interval; + param->opp_en.start_time = noa_attr.desc[0].start_time; } else { - if (param->mode_802_11i == 0) - param->mode_802_11i = 1; - rsn_idx += 4; - } - - rsn_idx += 7; - param->rsn_grp_policy = ies[rsn_idx]; - rsn_idx++; - offset = ies[rsn_idx] * 4; - pcipher_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx]; - rsn_idx += 2; - - i = *pcipher_tc; - j = 0; - for (; i < (pcipher_cnt + *pcipher_tc) && i < 3; i++, j++) { - u8 *policy = ¶m->rsn_pcip_policy[i]; - - *policy = ies[rsn_idx + ((j + 1) * 4) - 1]; + param->opp_enabled = 0; + param->opp_dis.cnt = noa_attr.desc[0].count; + param->opp_dis.duration = noa_attr.desc[0].duration; + param->opp_dis.interval = noa_attr.desc[0].interval; + param->opp_dis.start_time = noa_attr.desc[0].start_time; } - - *pcipher_tc += pcipher_cnt; - rsn_idx += offset; - - offset = ies[rsn_idx] * 4; - - auth_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx]; - rsn_idx += 2; - i = *auth_total_cnt; - j = 0; - for (; i < (*auth_total_cnt + auth_cnt); i++, j++) { - u8 *policy = ¶m->rsn_auth_policy[i]; - - *policy = ies[rsn_idx + ((j + 1) * 4) - 1]; + } + wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WMM, + ies->data, ies->len); + if (wmm_ie) { + struct ieee80211_wmm_param_ie *ie; + + ie = (struct ieee80211_wmm_param_ie *)wmm_ie; + if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) && + ie->version == 1) { + param->wmm_cap = true; + if (ie->qos_info & BIT(7)) + param->uapsd_cap = true; } + } - *auth_total_cnt += auth_cnt; - rsn_idx += offset; - - if (ies[index] == WLAN_EID_RSN) { - param->rsn_cap[0] = ies[rsn_idx]; - param->rsn_cap[1] = ies[rsn_idx + 1]; - rsn_idx += 2; - } + wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + ies->data, ies->len); + if (wpa_ie) { + param->mode_802_11i = 1; param->rsn_found = true; - index += ies[index + 1] + 2; - } else { - index += ies[index + 1] + 2; } - *out_index = index; -} - -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss) -{ - struct join_bss_param *param; - u16 index = 0; - u8 rates_no = 0; - u8 pcipher_total_cnt = 0; - u8 auth_total_cnt = 0; - const u8 *tim_elm, *ssid_elm; - const struct cfg80211_bss_ies *ies = bss->ies; + rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); + if (rsn_ie) { + int offset = 8; - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) - return NULL; - - param->beacon_period = bss->beacon_interval; - param->cap_info = bss->capability; - ether_addr_copy(param->bssid, bss->bssid); - - ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); - if (ssid_elm) { - param->ssid_len = ssid_elm[1]; - if (param->ssid_len <= IEEE80211_MAX_SSID_LEN) - memcpy(param->ssid, ssid_elm + 2, param->ssid_len); - else - param->ssid_len = 0; + param->mode_802_11i = 2; + param->rsn_found = true; + //extract RSN capabilities + offset += (rsn_ie[offset] * 4) + 2; + offset += (rsn_ie[offset] * 4) + 2; + memcpy(param->rsn_cap, &rsn_ie[offset], 2); } - tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); - if (tim_elm && tim_elm[1] >= 2) - param->dtim_period = tim_elm[3]; + if (param->rsn_found) { + int i; - memset(param->rsn_pcip_policy, 0xFF, 3); - memset(param->rsn_auth_policy, 0xFF, 3); + param->rsn_grp_policy = crypto->cipher_group & 0xFF; + for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++) + param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF; - while (index < ies->len) - host_int_fill_join_bss_param(param, ies->data, &index, - &pcipher_total_cnt, - &auth_total_cnt, ies->tsf, - &rates_no); + for (i = 0; i < crypto->n_akm_suites && i < 3; i++) + param->akm_suites[i] = crypto->akm_suites[i] & 0xFF; + } return (void *)param; } diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 76da17267e24..659e8ccb653b 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -35,21 +35,6 @@ enum { #define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256 -struct network_info { - s8 rssi; - u16 cap_info; - u8 ssid[MAX_SSID_LEN]; - u8 ssid_len; - u8 bssid[6]; - u16 beacon_period; - u8 dtim_period; - u8 ch; - u32 tsf_lo; - u8 *ies; - u16 ies_len; - u64 tsf; -}; - struct connect_info { u8 bssid[6]; u8 *req_ies; @@ -288,5 +273,6 @@ int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power); void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length); -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss); +void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto); #endif diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 5da03bb88ab4..5070cad27738 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -422,7 +422,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, goto out_put_bss; } - join_params = wilc_parse_join_bss_param(bss); + join_params = wilc_parse_join_bss_param(bss, &sme->crypto); if (!join_params) { netdev_err(dev, "%s: failed to construct join param\n", __func__); diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h index e2310d860291..961b6bb034a8 100644 --- a/drivers/staging/wilc1000/wilc_wlan_if.h +++ b/drivers/staging/wilc1000/wilc_wlan_if.h @@ -47,7 +47,6 @@ typedef void (*wilc_tx_complete_func_t)(void *, int); * ********************************************/ #define WILC_MULTICAST_TABLE_SIZE 8 -#define MAX_SSID_LEN 33 #define MAX_RATES_SUPPORTED 12 enum bss_types { -- cgit v1.2.3 From f47e59eaab27eb251971b23a991d1bac6e088841 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:30 +0000 Subject: staging: wilc1000: rename hidden_network related data structure Rename hidden_network related data structure to have more appropriate names, as it's used to keep search network SSID details. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 40 +++++++++++------------ drivers/staging/wilc1000/host_interface.h | 11 ++++--- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 25 +++++++------- 3 files changed, 38 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 46fd448ddde7..6c2be4339ce2 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -234,7 +234,7 @@ static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, u8 *ch_freq_list, u8 ch_list_len, const u8 *ies, size_t ies_len, wilc_scan_result scan_result, void *user_arg, - struct hidden_network *hidden_net) + struct wilc_probe_ssid *search) { int result = 0; struct wid wid_list[5]; @@ -242,7 +242,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, u32 i; u8 *buffer; u8 valuesize = 0; - u8 *hdn_ntwk_wid_val = NULL; + u8 *search_ssid_vals = NULL; struct host_if_drv *hif_drv = vif->hif_drv; if (hif_drv->hif_state >= HOST_IF_SCANNING && @@ -260,26 +260,24 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, hif_drv->usr_scan_req.ch_cnt = 0; - if (hidden_net) { - wid_list[index].id = WID_SSID_PROBE_REQ; - wid_list[index].type = WID_STR; - - for (i = 0; i < hidden_net->n_ssids; i++) - valuesize += ((hidden_net->net_info[i].ssid_len) + 1); - hdn_ntwk_wid_val = kmalloc(valuesize + 1, GFP_KERNEL); - wid_list[index].val = hdn_ntwk_wid_val; - if (wid_list[index].val) { + if (search) { + for (i = 0; i < search->n_ssids; i++) + valuesize += ((search->ssid_info[i].ssid_len) + 1); + search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL); + if (search_ssid_vals) { + wid_list[index].id = WID_SSID_PROBE_REQ; + wid_list[index].type = WID_STR; + wid_list[index].val = search_ssid_vals; buffer = wid_list[index].val; - *buffer++ = hidden_net->n_ssids; + *buffer++ = search->n_ssids; - for (i = 0; i < hidden_net->n_ssids; i++) { - *buffer++ = hidden_net->net_info[i].ssid_len; - memcpy(buffer, hidden_net->net_info[i].ssid, - hidden_net->net_info[i].ssid_len); - buffer += hidden_net->net_info[i].ssid_len; + for (i = 0; i < search->n_ssids; i++) { + *buffer++ = search->ssid_info[i].ssid_len; + memcpy(buffer, search->ssid_info[i].ssid, + search->ssid_info[i].ssid_len); + buffer += search->ssid_info[i].ssid_len; } - wid_list[index].size = (s32)(valuesize + 1); index++; } @@ -332,9 +330,9 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, jiffies + msecs_to_jiffies(HOST_IF_SCAN_TIMEOUT)); error: - if (hidden_net) { - kfree(hidden_net->net_info); - kfree(hdn_ntwk_wid_val); + if (search) { + kfree(search->ssid_info); + kfree(search_ssid_vals); } return result; diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 659e8ccb653b..e702404854f2 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -131,14 +131,15 @@ typedef void (*wilc_connect_result)(enum conn_event, typedef void (*wilc_remain_on_chan_expired)(void *, u32); typedef void (*wilc_remain_on_chan_ready)(void *); -struct hidden_net_info { - u8 *ssid; +struct wilc_probe_ssid_info { u8 ssid_len; + u8 *ssid; }; -struct hidden_network { - struct hidden_net_info *net_info; +struct wilc_probe_ssid { + struct wilc_probe_ssid_info *ssid_info; u8 n_ssids; + u32 size; }; struct user_scan_req { @@ -238,7 +239,7 @@ int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, u8 *ch_freq_list, u8 ch_list_len, const u8 *ies, size_t ies_len, wilc_scan_result scan_result, void *user_arg, - struct hidden_network *hidden_network); + struct wilc_probe_ssid *search); int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *cfg_param); int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler); diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 5070cad27738..1762c609962c 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -221,22 +221,23 @@ static int set_channel(struct wiphy *wiphy, static inline int wilc_wfi_cfg_alloc_fill_ssid(struct cfg80211_scan_request *request, - struct hidden_network *ntwk) + struct wilc_probe_ssid *search) { int i; int slot_id = 0; - ntwk->net_info = kcalloc(request->n_ssids, sizeof(*ntwk->net_info), - GFP_KERNEL); - if (!ntwk->net_info) + search->ssid_info = kcalloc(request->n_ssids, + sizeof(*search->ssid_info), GFP_KERNEL); + if (!search->ssid_info) goto out; - ntwk->n_ssids = request->n_ssids; + search->n_ssids = request->n_ssids; for (i = 0; i < request->n_ssids; i++) { if (request->ssids[i].ssid_len > 0) { - struct hidden_net_info *info = &ntwk->net_info[slot_id]; + struct wilc_probe_ssid_info *info; + info = &search->ssid_info[slot_id]; info->ssid = kmemdup(request->ssids[i].ssid, request->ssids[i].ssid_len, GFP_KERNEL); @@ -246,7 +247,7 @@ wilc_wfi_cfg_alloc_fill_ssid(struct cfg80211_scan_request *request, info->ssid_len = request->ssids[i].ssid_len; slot_id++; } else { - ntwk->n_ssids -= 1; + search->n_ssids -= 1; } } return 0; @@ -254,9 +255,9 @@ wilc_wfi_cfg_alloc_fill_ssid(struct cfg80211_scan_request *request, out_free: for (i = 0; i < slot_id; i++) - kfree(ntwk->net_info[i].ssid); + kfree(search->ssid_info[i].ssid); - kfree(ntwk->net_info); + kfree(search->ssid_info); out: return -ENOMEM; @@ -269,7 +270,7 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) u32 i; int ret = 0; u8 scan_ch_list[MAX_NUM_SCANNED_NETWORKS]; - struct hidden_network hidden_ntwk; + struct wilc_probe_ssid probe_ssid; priv->scan_req = request; @@ -283,7 +284,7 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) if (request->n_ssids >= 1) { if (wilc_wfi_cfg_alloc_fill_ssid(request, - &hidden_ntwk)) { + &probe_ssid)) { ret = -ENOMEM; goto out; } @@ -293,7 +294,7 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) request->n_channels, (const u8 *)request->ie, request->ie_len, cfg_scan_result, - (void *)priv, &hidden_ntwk); + (void *)priv, &probe_ssid); } else { ret = wilc_scan(vif, WILC_FW_USER_SCAN, WILC_FW_ACTIVE_SCAN, scan_ch_list, -- cgit v1.2.3 From 734c3198d06e74777a15fc1e036e1c3d571858fa Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:32 +0000 Subject: staging: wilc1000: use single struct for 'connect' related parameters Use single structure to store the connect request and response information. It helped in avoiding unnecessary buffer allocation to handle request and response flow. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 217 ++++++---------------- drivers/staging/wilc1000/host_interface.h | 41 ++-- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 30 +-- 3 files changed, 84 insertions(+), 204 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 6c2be4339ce2..e37d8abcb9d3 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -344,8 +344,8 @@ static int wilc_send_connect_wid(struct wilc_vif *vif) struct wid wid_list[8]; u32 wid_cnt = 0, dummyval = 0; struct host_if_drv *hif_drv = vif->hif_drv; - struct user_conn_req *conn_attr = &hif_drv->usr_conn_req; - struct wilc_join_bss_param *bss_param = hif_drv->usr_conn_req.param; + struct wilc_conn_info *conn_attr = &hif_drv->conn_info; + struct wilc_join_bss_param *bss_param = conn_attr->param; wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT; wid_list[wid_cnt].type = WID_INT; @@ -367,8 +367,8 @@ static int wilc_send_connect_wid(struct wilc_vif *vif) wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE; wid_list[wid_cnt].type = WID_BIN_DATA; - wid_list[wid_cnt].val = conn_attr->ies; - wid_list[wid_cnt].size = conn_attr->ies_len; + wid_list[wid_cnt].val = conn_attr->req_ies; + wid_list[wid_cnt].size = conn_attr->req_ies_len; wid_cnt++; wid_list[wid_cnt].id = WID_11I_MODE; @@ -403,14 +403,8 @@ static int wilc_send_connect_wid(struct wilc_vif *vif) error: - kfree(conn_attr->bssid); - conn_attr->bssid = NULL; - - kfree(conn_attr->ssid); - conn_attr->ssid = NULL; - - kfree(conn_attr->ies); - conn_attr->ies = NULL; + kfree(conn_attr->req_ies); + conn_attr->req_ies = NULL; return result; } @@ -420,7 +414,6 @@ static void handle_connect_timeout(struct work_struct *work) struct host_if_msg *msg = container_of(work, struct host_if_msg, work); struct wilc_vif *vif = msg->vif; int result; - struct connect_info info; struct wid wid; u16 dummy_reason_code = 0; struct host_if_drv *hif_drv = vif->hif_drv; @@ -432,31 +425,11 @@ static void handle_connect_timeout(struct work_struct *work) hif_drv->hif_state = HOST_IF_IDLE; - memset(&info, 0, sizeof(struct connect_info)); - - if (hif_drv->usr_conn_req.conn_result) { - if (hif_drv->usr_conn_req.bssid) { - memcpy(info.bssid, - hif_drv->usr_conn_req.bssid, 6); - } - - if (hif_drv->usr_conn_req.ies) { - info.req_ies_len = hif_drv->usr_conn_req.ies_len; - info.req_ies = kmemdup(hif_drv->usr_conn_req.ies, - hif_drv->usr_conn_req.ies_len, - GFP_KERNEL); - if (!info.req_ies) - goto out; - } - - hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP, - &info, - WILC_MAC_STATUS_DISCONNECTED, - NULL, - hif_drv->usr_conn_req.arg); + if (hif_drv->conn_info.conn_result) { + hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP, + WILC_MAC_STATUS_DISCONNECTED, + NULL, hif_drv->conn_info.arg); - kfree(info.req_ies); - info.req_ies = NULL; } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); } @@ -471,14 +444,9 @@ static void handle_connect_timeout(struct work_struct *work) if (result) netdev_err(vif->ndev, "Failed to send disconnect\n"); - hif_drv->usr_conn_req.ssid_len = 0; - kfree(hif_drv->usr_conn_req.ssid); - hif_drv->usr_conn_req.ssid = NULL; - kfree(hif_drv->usr_conn_req.bssid); - hif_drv->usr_conn_req.bssid = NULL; - hif_drv->usr_conn_req.ies_len = 0; - kfree(hif_drv->usr_conn_req.ies); - hif_drv->usr_conn_req.ies = NULL; + hif_drv->conn_info.req_ies_len = 0; + kfree(hif_drv->conn_info.req_ies); + hif_drv->conn_info.req_ies = NULL; out: kfree(msg); @@ -671,20 +639,8 @@ static void host_int_get_assoc_res_info(struct wilc_vif *vif, *rcvd_assoc_resp_info_len = wid.size; } -static inline void host_int_free_user_conn_req(struct host_if_drv *hif_drv) -{ - hif_drv->usr_conn_req.ssid_len = 0; - kfree(hif_drv->usr_conn_req.ssid); - hif_drv->usr_conn_req.ssid = NULL; - kfree(hif_drv->usr_conn_req.bssid); - hif_drv->usr_conn_req.bssid = NULL; - hif_drv->usr_conn_req.ies_len = 0; - kfree(hif_drv->usr_conn_req.ies); - hif_drv->usr_conn_req.ies = NULL; -} - static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len, - struct connect_info *ret_conn_info) + struct wilc_conn_info *ret_conn_info) { u8 *ies; u16 ies_len; @@ -708,10 +664,8 @@ static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len, static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, u8 mac_status) { - struct connect_info conn_info; struct host_if_drv *hif_drv = vif->hif_drv; - - memset(&conn_info, 0, sizeof(struct connect_info)); + struct wilc_conn_info *conn_info = &hif_drv->conn_info; if (mac_status == WILC_MAC_STATUS_CONNECTED) { u32 assoc_resp_info_len; @@ -727,7 +681,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp, assoc_resp_info_len, - &conn_info); + conn_info); if (err) netdev_err(vif->ndev, "wilc_parse_assoc_resp_info() returned error %d\n", @@ -735,31 +689,13 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, } } - if (hif_drv->usr_conn_req.bssid) { - memcpy(conn_info.bssid, hif_drv->usr_conn_req.bssid, 6); - - if (mac_status == WILC_MAC_STATUS_CONNECTED && - conn_info.status == WLAN_STATUS_SUCCESS) { - memcpy(hif_drv->assoc_bssid, - hif_drv->usr_conn_req.bssid, ETH_ALEN); - } - } - - if (hif_drv->usr_conn_req.ies) { - conn_info.req_ies = kmemdup(hif_drv->usr_conn_req.ies, - hif_drv->usr_conn_req.ies_len, - GFP_KERNEL); - if (conn_info.req_ies) - conn_info.req_ies_len = hif_drv->usr_conn_req.ies_len; - } - del_timer(&hif_drv->connect_timer); - hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP, - &conn_info, mac_status, NULL, - hif_drv->usr_conn_req.arg); + conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, NULL, + hif_drv->conn_info.arg); if (mac_status == WILC_MAC_STATUS_CONNECTED && - conn_info.status == WLAN_STATUS_SUCCESS) { + conn_info->status == WLAN_STATUS_SUCCESS) { + ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid); wilc_set_power_mgmt(vif, 0, 0); hif_drv->hif_state = HOST_IF_CONNECTED; @@ -771,19 +707,19 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, hif_drv->hif_state = HOST_IF_IDLE; } - kfree(conn_info.resp_ies); - conn_info.resp_ies = NULL; + kfree(conn_info->resp_ies); + conn_info->resp_ies = NULL; + conn_info->resp_ies_len = 0; - kfree(conn_info.req_ies); - conn_info.req_ies = NULL; - host_int_free_user_conn_req(hif_drv); + kfree(conn_info->req_ies); + conn_info->req_ies = NULL; + conn_info->req_ies_len = 0; } static inline void host_int_handle_disconnect(struct wilc_vif *vif) { struct disconnect_info disconn_info; struct host_if_drv *hif_drv = vif->hif_drv; - wilc_connect_result conn_result = hif_drv->usr_conn_req.conn_result; memset(&disconn_info, 0, sizeof(struct disconnect_info)); @@ -796,19 +732,22 @@ static inline void host_int_handle_disconnect(struct wilc_vif *vif) disconn_info.ie = NULL; disconn_info.ie_len = 0; - if (conn_result) { + if (hif_drv->conn_info.conn_result) { vif->obtaining_ip = false; wilc_set_power_mgmt(vif, 0, 0); - conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL, 0, - &disconn_info, hif_drv->usr_conn_req.arg); + hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, + 0, &disconn_info, + hif_drv->conn_info.arg); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); } eth_zero_addr(hif_drv->assoc_bssid); - host_int_free_user_conn_req(hif_drv); + hif_drv->conn_info.req_ies_len = 0; + kfree(hif_drv->conn_info.req_ies); + hif_drv->conn_info.req_ies = NULL; hif_drv->hif_state = HOST_IF_IDLE; } @@ -834,7 +773,7 @@ static void handle_rcvd_gnrl_async_info(struct work_struct *work) if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP || hif_drv->hif_state == HOST_IF_CONNECTED || hif_drv->usr_scan_req.scan_result) { - if (!hif_drv->usr_conn_req.conn_result) { + if (!hif_drv->conn_info.conn_result) { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); goto free_rcvd_info; @@ -875,7 +814,7 @@ int wilc_disconnect(struct wilc_vif *vif) struct host_if_drv *hif_drv = vif->hif_drv; struct disconnect_info disconn_info; struct user_scan_req *scan_req; - struct user_conn_req *conn_req; + struct wilc_conn_info *conn_info; int result; u16 dummy_reason_code = 0; @@ -900,7 +839,7 @@ int wilc_disconnect(struct wilc_vif *vif) disconn_info.ie = NULL; disconn_info.ie_len = 0; scan_req = &hif_drv->usr_scan_req; - conn_req = &hif_drv->usr_conn_req; + conn_info = &hif_drv->conn_info; if (scan_req->scan_result) { del_timer(&hif_drv->scan_timer); @@ -908,12 +847,12 @@ int wilc_disconnect(struct wilc_vif *vif) scan_req->scan_result = NULL; } - if (conn_req->conn_result) { + if (conn_info->conn_result) { if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) del_timer(&hif_drv->connect_timer); - conn_req->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL, - 0, &disconn_info, conn_req->arg); + conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, + 0, &disconn_info, conn_info->arg); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); } @@ -922,14 +861,9 @@ int wilc_disconnect(struct wilc_vif *vif) eth_zero_addr(hif_drv->assoc_bssid); - conn_req->ssid_len = 0; - kfree(conn_req->ssid); - conn_req->ssid = NULL; - kfree(conn_req->bssid); - conn_req->bssid = NULL; - conn_req->ies_len = 0; - kfree(conn_req->ies); - conn_req->ies = NULL; + conn_info->req_ies_len = 0; + kfree(conn_info->req_ies); + conn_info->req_ies = NULL; return 0; } @@ -1546,61 +1480,22 @@ int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr) return result; } -int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ssid, - size_t ssid_len, const u8 *ies, size_t ies_len, - wilc_connect_result connect_result, void *user_arg, - u8 security, enum authtype auth_type, - u8 channel, void *join_params) +int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, + size_t ies_len) { int result; struct host_if_drv *hif_drv = vif->hif_drv; - struct user_conn_req *con_info = &hif_drv->usr_conn_req; + struct wilc_conn_info *conn_info = &hif_drv->conn_info; - if (!hif_drv || !connect_result) { - netdev_err(vif->ndev, - "%s: hif driver or connect result is NULL", - __func__); - return -EFAULT; - } - - if (!join_params) { - netdev_err(vif->ndev, "%s: joinparams is NULL\n", __func__); - return -EFAULT; - } - - if (hif_drv->usr_scan_req.scan_result) { - netdev_err(vif->ndev, "%s: Scan in progress\n", __func__); - return -EBUSY; - } - - con_info->security = security; - con_info->auth_type = auth_type; - con_info->ch = channel; - con_info->conn_result = connect_result; - con_info->arg = user_arg; - con_info->param = join_params; - - if (bssid) { - con_info->bssid = kmemdup(bssid, 6, GFP_KERNEL); - if (!con_info->bssid) - return -ENOMEM; - } - - if (ssid) { - con_info->ssid_len = ssid_len; - con_info->ssid = kmemdup(ssid, ssid_len, GFP_KERNEL); - if (!con_info->ssid) { - result = -ENOMEM; - goto free_bssid; - } - } + if (bssid) + ether_addr_copy(conn_info->bssid, bssid); if (ies) { - con_info->ies_len = ies_len; - con_info->ies = kmemdup(ies, ies_len, GFP_KERNEL); - if (!con_info->ies) { + conn_info->req_ies_len = ies_len; + conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL); + if (!conn_info->req_ies) { result = -ENOMEM; - goto free_ssid; + return result; } } @@ -1615,13 +1510,7 @@ int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ssid, return 0; free_ies: - kfree(con_info->ies); - -free_ssid: - kfree(con_info->ssid); - -free_bssid: - kfree(con_info->bssid); + kfree(conn_info->req_ies); return result; } @@ -1963,7 +1852,7 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) return; } - if (!hif_drv->usr_conn_req.conn_result) { + if (!hif_drv->conn_info.conn_result) { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); mutex_unlock(&hif_deinit_lock); return; diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index e702404854f2..459a0847f7df 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -35,15 +35,6 @@ enum { #define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256 -struct connect_info { - u8 bssid[6]; - u8 *req_ies; - size_t req_ies_len; - u8 *resp_ies; - u16 resp_ies_len; - u16 status; -}; - struct disconnect_info { u16 reason; u8 *ie; @@ -122,12 +113,6 @@ struct wilc_rcvd_net_info { typedef void (*wilc_scan_result)(enum scan_event, struct wilc_rcvd_net_info *, void *); -typedef void (*wilc_connect_result)(enum conn_event, - struct connect_info *, - u8, - struct disconnect_info *, - void *); - typedef void (*wilc_remain_on_chan_expired)(void *, u32); typedef void (*wilc_remain_on_chan_ready)(void *); @@ -148,17 +133,18 @@ struct user_scan_req { u32 ch_cnt; }; -struct user_conn_req { - u8 *bssid; - u8 *ssid; +struct wilc_conn_info { + u8 bssid[ETH_ALEN]; u8 security; enum authtype auth_type; - size_t ssid_len; - u8 *ies; - size_t ies_len; - wilc_connect_result conn_result; - bool ht_capable; u8 ch; + u8 *req_ies; + size_t req_ies_len; + u8 *resp_ies; + u16 resp_ies_len; + u16 status; + void (*conn_result)(enum conn_event evt, u8 status, + struct disconnect_info *info, void *priv_data); void *arg; void *param; }; @@ -175,7 +161,7 @@ struct remain_ch { struct wilc; struct host_if_drv { struct user_scan_req usr_scan_req; - struct user_conn_req usr_conn_req; + struct wilc_conn_info conn_info; struct remain_ch remain_on_ch; u8 remain_on_ch_pending; u64 p2p_timeout; @@ -228,11 +214,8 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, u8 cipher_mode); int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid); int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr); -int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ssid, - size_t ssid_len, const u8 *ies, size_t ies_len, - wilc_connect_result connect_result, void *user_arg, - u8 security, enum authtype auth_type, - u8 channel, void *join_params); +int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, + size_t ies_len); int wilc_disconnect(struct wilc_vif *vif); int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel); int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 1762c609962c..bc1d7a70d14c 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -139,9 +139,7 @@ static void cfg_scan_result(enum scan_event scan_event, } } -static void cfg_connect_result(enum conn_event conn_disconn_evt, - struct connect_info *conn_info, - u8 mac_status, +static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, struct disconnect_info *disconn_info, void *priv_data) { @@ -150,16 +148,15 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, struct wilc_vif *vif = netdev_priv(dev); struct wilc *wl = vif->wilc; struct host_if_drv *wfi_drv = priv->hif_drv; + struct wilc_conn_info *conn_info = &wfi_drv->conn_info; vif->connecting = false; if (conn_disconn_evt == CONN_DISCONN_EVENT_CONN_RESP) { - u16 connect_status; - - connect_status = conn_info->status; + u16 connect_status = conn_info->status; if (mac_status == WILC_MAC_STATUS_DISCONNECTED && - conn_info->status == WLAN_STATUS_SUCCESS) { + connect_status == WLAN_STATUS_SUCCESS) { connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE; wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE); @@ -410,6 +407,12 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, auth_type = WILC_FW_AUTH_IEEE8021; } + if (wfi_drv->usr_scan_req.scan_result) { + netdev_err(vif->ndev, "%s: Scan in progress\n", __func__); + ret = -EBUSY; + goto out_error; + } + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY(sme->privacy)); @@ -438,16 +441,21 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, wilc_wlan_set_bssid(dev, bss->bssid, WILC_STATION_MODE); - ret = wilc_set_join_req(vif, bss->bssid, sme->ssid, - sme->ssid_len, sme->ie, sme->ie_len, - cfg_connect_result, (void *)priv, - security, auth_type, curr_channel, join_params); + wfi_drv->conn_info.security = security; + wfi_drv->conn_info.auth_type = auth_type; + wfi_drv->conn_info.ch = curr_channel; + wfi_drv->conn_info.conn_result = cfg_connect_result; + wfi_drv->conn_info.arg = priv; + wfi_drv->conn_info.param = join_params; + + ret = wilc_set_join_req(vif, bss->bssid, sme->ie, sme->ie_len); if (ret) { netdev_err(dev, "wilc_set_join_req(): Error\n"); ret = -ENOENT; if (!wfi_drv->p2p_connect) wlan_channel = INVALID_CHANNEL; wilc_wlan_set_bssid(dev, NULL, WILC_STATION_MODE); + wfi_drv->conn_info.conn_result = NULL; kfree(join_params); goto out_put_bss; } -- cgit v1.2.3 From 94bb6d3353c21feb02c27eb1ee3feb2beaeecde4 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:35 +0000 Subject: staging: wilc1000: refactor information message parsing logic Refactor code to avoid maintaining an unnecessary buffer to keep the information type message ('I' msg type). Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 66 ++++++++----------------------- 1 file changed, 16 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index e37d8abcb9d3..a146b7810b2a 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -11,9 +11,8 @@ #define FALSE_FRMWR_CHANNEL 100 -struct rcvd_async_info { - u8 *buffer; - u32 len; +struct wilc_rcvd_mac_info { + u8 status; }; struct set_multicast { @@ -71,7 +70,7 @@ struct wilc_gtk_key { union message_body { struct wilc_rcvd_net_info net_info; - struct rcvd_async_info async_info; + struct wilc_rcvd_mac_info mac_info; struct set_multicast multicast_info; struct remain_ch remain_on_ch; char *data; @@ -755,55 +754,30 @@ static void handle_rcvd_gnrl_async_info(struct work_struct *work) { struct host_if_msg *msg = container_of(work, struct host_if_msg, work); struct wilc_vif *vif = msg->vif; - struct rcvd_async_info *rcvd_info = &msg->body.async_info; - u8 msg_type; - u8 mac_status; + struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info; struct host_if_drv *hif_drv = vif->hif_drv; - if (!rcvd_info->buffer) { - netdev_err(vif->ndev, "%s: buffer is NULL\n", __func__); - goto free_msg; - } - if (!hif_drv) { netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__); - goto free_rcvd_info; + goto free_msg; } - if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP || - hif_drv->hif_state == HOST_IF_CONNECTED || - hif_drv->usr_scan_req.scan_result) { - if (!hif_drv->conn_info.conn_result) { - netdev_err(vif->ndev, "%s: conn_result is NULL\n", - __func__); - goto free_rcvd_info; - } - - msg_type = rcvd_info->buffer[0]; - - if ('I' != msg_type) { - netdev_err(vif->ndev, "Received Message incorrect.\n"); - goto free_rcvd_info; - } + if (!hif_drv->conn_info.conn_result) { + netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); + goto free_msg; + } - mac_status = rcvd_info->buffer[7]; - if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { - host_int_parse_assoc_resp_info(vif, mac_status); - } else if ((mac_status == WILC_MAC_STATUS_DISCONNECTED) && - (hif_drv->hif_state == HOST_IF_CONNECTED)) { + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { + host_int_parse_assoc_resp_info(vif, mac_info->status); + } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) { + if (hif_drv->hif_state == HOST_IF_CONNECTED) { host_int_handle_disconnect(vif); - } else if ((mac_status == WILC_MAC_STATUS_DISCONNECTED) && - (hif_drv->usr_scan_req.scan_result)) { + } else if (hif_drv->usr_scan_req.scan_result) { del_timer(&hif_drv->scan_timer); - if (hif_drv->usr_scan_req.scan_result) - handle_scan_done(vif, SCAN_EVENT_ABORTED); + handle_scan_done(vif, SCAN_EVENT_ABORTED); } } -free_rcvd_info: - kfree(rcvd_info->buffer); - rcvd_info->buffer = NULL; - free_msg: kfree(msg); } @@ -1864,18 +1838,10 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) return; } - msg->body.async_info.len = length; - msg->body.async_info.buffer = kmemdup(buffer, length, GFP_KERNEL); - if (!msg->body.async_info.buffer) { - kfree(msg); - mutex_unlock(&hif_deinit_lock); - return; - } - + msg->body.mac_info.status = buffer[7]; result = wilc_enqueue_work(msg); if (result) { netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); - kfree(msg->body.async_info.buffer); kfree(msg); } -- cgit v1.2.3 From 03cf31c41c2206731100aad51b98142b9e131fbb Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:38 +0000 Subject: staging: wilc1000: remove 'disconnect_info' structure Remove 'disconnect_info' struct use because its passed values are not required in cfg_connect_result(). Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 24 +++++------------------ drivers/staging/wilc1000/host_interface.h | 9 +-------- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 12 ++++++------ 3 files changed, 12 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index a146b7810b2a..fa3af2c6bee6 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -427,7 +427,7 @@ static void handle_connect_timeout(struct work_struct *work) if (hif_drv->conn_info.conn_result) { hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP, WILC_MAC_STATUS_DISCONNECTED, - NULL, hif_drv->conn_info.arg); + hif_drv->conn_info.arg); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); @@ -689,7 +689,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, } del_timer(&hif_drv->connect_timer); - conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, NULL, + conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, hif_drv->conn_info.arg); if (mac_status == WILC_MAC_STATUS_CONNECTED && @@ -717,27 +717,19 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, static inline void host_int_handle_disconnect(struct wilc_vif *vif) { - struct disconnect_info disconn_info; struct host_if_drv *hif_drv = vif->hif_drv; - memset(&disconn_info, 0, sizeof(struct disconnect_info)); - if (hif_drv->usr_scan_req.scan_result) { del_timer(&hif_drv->scan_timer); handle_scan_done(vif, SCAN_EVENT_ABORTED); } - disconn_info.reason = 0; - disconn_info.ie = NULL; - disconn_info.ie_len = 0; - if (hif_drv->conn_info.conn_result) { vif->obtaining_ip = false; wilc_set_power_mgmt(vif, 0, 0); hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, - 0, &disconn_info, - hif_drv->conn_info.arg); + 0, hif_drv->conn_info.arg); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); } @@ -786,7 +778,6 @@ int wilc_disconnect(struct wilc_vif *vif) { struct wid wid; struct host_if_drv *hif_drv = vif->hif_drv; - struct disconnect_info disconn_info; struct user_scan_req *scan_req; struct wilc_conn_info *conn_info; int result; @@ -807,11 +798,6 @@ int wilc_disconnect(struct wilc_vif *vif) return result; } - memset(&disconn_info, 0, sizeof(struct disconnect_info)); - - disconn_info.reason = 0; - disconn_info.ie = NULL; - disconn_info.ie_len = 0; scan_req = &hif_drv->usr_scan_req; conn_info = &hif_drv->conn_info; @@ -825,8 +811,8 @@ int wilc_disconnect(struct wilc_vif *vif) if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) del_timer(&hif_drv->connect_timer); - conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, - 0, &disconn_info, conn_info->arg); + conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0, + conn_info->arg); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); } diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 459a0847f7df..363db0b9fea8 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -35,12 +35,6 @@ enum { #define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256 -struct disconnect_info { - u16 reason; - u8 *ie; - size_t ie_len; -}; - struct assoc_resp { __le16 capab_info; __le16 status_code; @@ -143,8 +137,7 @@ struct wilc_conn_info { u8 *resp_ies; u16 resp_ies_len; u16 status; - void (*conn_result)(enum conn_event evt, u8 status, - struct disconnect_info *info, void *priv_data); + void (*conn_result)(enum conn_event evt, u8 status, void *priv_data); void *arg; void *param; }; diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index bc1d7a70d14c..79753ad15b7c 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -140,7 +140,6 @@ static void cfg_scan_result(enum scan_event scan_event, } static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, - struct disconnect_info *disconn_info, void *priv_data) { struct wilc_priv *priv = priv_data; @@ -177,6 +176,8 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, conn_info->resp_ies_len, connect_status, GFP_KERNEL); } else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) { + u16 reason = 0; + vif->obtaining_ip = false; priv->p2p.local_random = 0x01; priv->p2p.recv_random = 0x00; @@ -186,14 +187,13 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, if (!wfi_drv->p2p_connect) wlan_channel = INVALID_CHANNEL; + if (wfi_drv->ifc_up && dev == wl->vif[1]->ndev) - disconn_info->reason = 3; + reason = 3; else if (!wfi_drv->ifc_up && dev == wl->vif[1]->ndev) - disconn_info->reason = 1; + reason = 1; - cfg80211_disconnected(dev, disconn_info->reason, - disconn_info->ie, disconn_info->ie_len, - false, GFP_KERNEL); + cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL); } } -- cgit v1.2.3 From a0c6a32e78a078fd5fa589ae2670155088e3a741 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:41 +0000 Subject: staging: wilc1000: refactor handle_set_mcast_filter() Refactor handle_set_mcast_filter() by making use of put_unaligned32() to pack the data instead of byte operation. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 37 +++++++++++++------------------ drivers/staging/wilc1000/host_interface.h | 2 +- drivers/staging/wilc1000/linux_wlan.c | 6 ++--- 3 files changed, 20 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index fa3af2c6bee6..f4638654d1a5 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -15,8 +15,8 @@ struct wilc_rcvd_mac_info { u8 status; }; -struct set_multicast { - bool enabled; +struct wilc_set_multicast { + u32 enabled; u32 cnt; u8 *mc_list; }; @@ -71,7 +71,7 @@ struct wilc_gtk_key { union message_body { struct wilc_rcvd_net_info net_info; struct wilc_rcvd_mac_info mac_info; - struct set_multicast multicast_info; + struct wilc_set_multicast mc_info; struct remain_ch remain_on_ch; char *data; }; @@ -1067,32 +1067,27 @@ static void handle_set_mcast_filter(struct work_struct *work) { struct host_if_msg *msg = container_of(work, struct host_if_msg, work); struct wilc_vif *vif = msg->vif; - struct set_multicast *hif_set_mc = &msg->body.multicast_info; + struct wilc_set_multicast *set_mc = &msg->body.mc_info; int result; struct wid wid; u8 *cur_byte; wid.id = WID_SETUP_MULTICAST_FILTER; wid.type = WID_BIN; - wid.size = sizeof(struct set_multicast) + (hif_set_mc->cnt * ETH_ALEN); + wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN); wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) goto error; cur_byte = wid.val; - *cur_byte++ = (hif_set_mc->enabled & 0xFF); - *cur_byte++ = 0; - *cur_byte++ = 0; - *cur_byte++ = 0; + put_unaligned_le32(set_mc->enabled, cur_byte); + cur_byte += 4; - *cur_byte++ = (hif_set_mc->cnt & 0xFF); - *cur_byte++ = ((hif_set_mc->cnt >> 8) & 0xFF); - *cur_byte++ = ((hif_set_mc->cnt >> 16) & 0xFF); - *cur_byte++ = ((hif_set_mc->cnt >> 24) & 0xFF); + put_unaligned_le32(set_mc->cnt, cur_byte); + cur_byte += 4; - if (hif_set_mc->cnt > 0 && hif_set_mc->mc_list) - memcpy(cur_byte, hif_set_mc->mc_list, - ((hif_set_mc->cnt) * ETH_ALEN)); + if (set_mc->cnt > 0 && set_mc->mc_list) + memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN); result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); @@ -1100,7 +1095,7 @@ static void handle_set_mcast_filter(struct work_struct *work) netdev_err(vif->ndev, "Failed to send setup multicast\n"); error: - kfree(hif_set_mc->mc_list); + kfree(set_mc->mc_list); kfree(wid.val); kfree(msg); } @@ -2150,7 +2145,7 @@ int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout) return result; } -int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, u32 count, +int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, u8 *mc_list) { int result; @@ -2160,9 +2155,9 @@ int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, u32 count, if (IS_ERR(msg)) return PTR_ERR(msg); - msg->body.multicast_info.enabled = enabled; - msg->body.multicast_info.cnt = count; - msg->body.multicast_info.mc_list = mc_list; + msg->body.mc_info.enabled = enabled; + msg->body.mc_info.cnt = count; + msg->body.mc_info.mc_list = mc_list; result = wilc_enqueue_work(msg); if (result) { diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 363db0b9fea8..527ae0523d67 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -230,7 +230,7 @@ int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr); int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, struct station_parameters *params); int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout); -int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, u32 count, +int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, u8 *mc_list); int wilc_remain_on_channel(struct wilc_vif *vif, u32 session_id, u32 duration, u16 chan, diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 5b554c6d39a1..87ec048824b8 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -811,12 +811,12 @@ static void wilc_set_multicast_list(struct net_device *dev) if (dev->flags & IFF_ALLMULTI || dev->mc.count > WILC_MULTICAST_TABLE_SIZE) { - wilc_setup_multicast_filter(vif, false, 0, NULL); + wilc_setup_multicast_filter(vif, 0, 0, NULL); return; } if (dev->mc.count == 0) { - wilc_setup_multicast_filter(vif, true, 0, NULL); + wilc_setup_multicast_filter(vif, 1, 0, NULL); return; } @@ -833,7 +833,7 @@ static void wilc_set_multicast_list(struct net_device *dev) cur_mc += ETH_ALEN; } - if (wilc_setup_multicast_filter(vif, true, dev->mc.count, mc_list)) + if (wilc_setup_multicast_filter(vif, 1, dev->mc.count, mc_list)) kfree(mc_list); } -- cgit v1.2.3 From 65af887c3dfb87e244877dc28d0cceac8b60b6be Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 17 Jan 2019 13:21:44 +0000 Subject: staging: wilc1000: avoid the use of typedef for function pointers Remove typedef for function pointers. Signed-off-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 13 +++++++------ drivers/staging/wilc1000/host_interface.h | 24 ++++++++++-------------- drivers/staging/wilc1000/wilc_wlan.c | 10 ++++++---- drivers/staging/wilc1000/wilc_wlan.h | 5 +++-- drivers/staging/wilc1000/wilc_wlan_if.h | 2 -- 5 files changed, 26 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index f4638654d1a5..85573eb400af 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -231,9 +231,10 @@ static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) } int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, const u8 *ies, - size_t ies_len, wilc_scan_result scan_result, void *user_arg, - struct wilc_probe_ssid *search) + u8 *ch_freq_list, u8 ch_list_len, const u8 *ies, size_t ies_len, + void (*scan_result_fn)(enum scan_event, + struct wilc_rcvd_net_info *, void *), + void *user_arg, struct wilc_probe_ssid *search) { int result = 0; struct wid wid_list[5]; @@ -322,7 +323,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, goto error; } - hif_drv->usr_scan_req.scan_result = scan_result; + hif_drv->usr_scan_req.scan_result = scan_result_fn; hif_drv->usr_scan_req.arg = user_arg; hif_drv->scan_timer_vif = vif; mod_timer(&hif_drv->scan_timer, @@ -1863,8 +1864,8 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) int wilc_remain_on_channel(struct wilc_vif *vif, u32 session_id, u32 duration, u16 chan, - wilc_remain_on_chan_expired expired, - wilc_remain_on_chan_ready ready, + void (*expired)(void *, u32), + void (*ready)(void *), void *user_arg) { struct remain_ch roc; diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 527ae0523d67..7f3fc4c8cb8f 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -104,12 +104,6 @@ struct wilc_rcvd_net_info { struct ieee80211_mgmt *mgmt; }; -typedef void (*wilc_scan_result)(enum scan_event, struct wilc_rcvd_net_info *, - void *); - -typedef void (*wilc_remain_on_chan_expired)(void *, u32); -typedef void (*wilc_remain_on_chan_ready)(void *); - struct wilc_probe_ssid_info { u8 ssid_len; u8 *ssid; @@ -122,7 +116,8 @@ struct wilc_probe_ssid { }; struct user_scan_req { - wilc_scan_result scan_result; + void (*scan_result)(enum scan_event evt, + struct wilc_rcvd_net_info *info, void *priv); void *arg; u32 ch_cnt; }; @@ -145,8 +140,8 @@ struct wilc_conn_info { struct remain_ch { u16 ch; u32 duration; - wilc_remain_on_chan_expired expired; - wilc_remain_on_chan_ready ready; + void (*expired)(void *priv, u32 session_id); + void (*ready)(void *priv); void *arg; u32 id; }; @@ -213,9 +208,10 @@ int wilc_disconnect(struct wilc_vif *vif); int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel); int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, const u8 *ies, - size_t ies_len, wilc_scan_result scan_result, void *user_arg, - struct wilc_probe_ssid *search); + u8 *ch_freq_list, u8 ch_list_len, const u8 *ies, size_t ies_len, + void (*scan_result_fn)(enum scan_event, + struct wilc_rcvd_net_info *, void *), + void *user_arg, struct wilc_probe_ssid *search); int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *cfg_param); int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler); @@ -234,8 +230,8 @@ int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, u8 *mc_list); int wilc_remain_on_channel(struct wilc_vif *vif, u32 session_id, u32 duration, u16 chan, - wilc_remain_on_chan_expired expired, - wilc_remain_on_chan_ready ready, + void (*expired)(void *, u32), + void (*ready)(void *), void *user_arg); int wilc_listen_state_expired(struct wilc_vif *vif, u32 session_id); void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg); diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 16b6c5552432..9d3aaae2e74a 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -274,7 +274,8 @@ static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer, } int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, - u32 buffer_size, wilc_tx_complete_func_t func) + u32 buffer_size, + void (*tx_complete_fn)(void *, int)) { struct txq_entry_t *tqe; struct wilc_vif *vif = netdev_priv(dev); @@ -292,7 +293,7 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, tqe->type = WILC_NET_PKT; tqe->buffer = buffer; tqe->buffer_size = buffer_size; - tqe->tx_complete_func = func; + tqe->tx_complete_func = tx_complete_fn; tqe->priv = priv; tqe->ack_idx = NOT_TCP_ACK; @@ -303,7 +304,8 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, } int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, - u32 buffer_size, wilc_tx_complete_func_t func) + u32 buffer_size, + void (*tx_complete_fn)(void *, int)) { struct txq_entry_t *tqe; struct wilc_vif *vif = netdev_priv(dev); @@ -321,7 +323,7 @@ int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, tqe->type = WILC_MGMT_PKT; tqe->buffer = buffer; tqe->buffer_size = buffer_size; - tqe->tx_complete_func = func; + tqe->tx_complete_func = tx_complete_fn; tqe->priv = priv; tqe->ack_idx = NOT_TCP_ACK; wilc_wlan_txq_add_to_tail(dev, tqe); diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h index c8ca13b34691..388045283dd5 100644 --- a/drivers/staging/wilc1000/wilc_wlan.h +++ b/drivers/staging/wilc1000/wilc_wlan.h @@ -275,7 +275,8 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, int wilc_wlan_start(struct wilc *wilc); int wilc_wlan_stop(struct wilc *wilc); int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, - u32 buffer_size, wilc_tx_complete_func_t func); + u32 buffer_size, + void (*tx_complete_fn)(void *, int)); int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count); void wilc_handle_isr(struct wilc *wilc); void wilc_wlan_cleanup(struct net_device *dev); @@ -286,7 +287,7 @@ int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size); int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, - u32 buffer_size, wilc_tx_complete_func_t func); + u32 buffer_size, void (*func)(void *, int)); void wilc_chip_sleep_manually(struct wilc *wilc); void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value); diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h index 961b6bb034a8..9370caaf2059 100644 --- a/drivers/staging/wilc1000/wilc_wlan_if.h +++ b/drivers/staging/wilc1000/wilc_wlan_if.h @@ -39,8 +39,6 @@ struct tx_complete_data { struct sk_buff *skb; }; -typedef void (*wilc_tx_complete_func_t)(void *, int); - /******************************************** * * Wlan Configuration ID -- cgit v1.2.3 From 32462a98a0051b45c1d41e305e3803a5094da417 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:10 -0600 Subject: staging: android: ion: Add proper header information The filenames in headers add nothing are often wrong after moves, lets drop them here and add a little description of the files contents. Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.c | 2 +- drivers/staging/android/ion/ion.h | 2 +- drivers/staging/android/ion/ion_carveout_heap.c | 2 +- drivers/staging/android/ion/ion_chunk_heap.c | 2 +- drivers/staging/android/ion/ion_cma_heap.c | 2 +- drivers/staging/android/ion/ion_heap.c | 2 +- drivers/staging/android/ion/ion_page_pool.c | 2 +- drivers/staging/android/ion/ion_system_heap.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index a0802de8c3a1..de1ca5e26a4a 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * drivers/staging/android/ion/ion.c + * ION Memory Allocator * * Copyright (C) 2011 Google, Inc. */ diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index 47b594cf1ac9..ff455fdde1a8 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * drivers/staging/android/ion/ion.h + * ION Memory Allocator kernel interface header * * Copyright (C) 2011 Google, Inc. */ diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index e129237a0417..4a9f9c275654 100644 --- a/drivers/staging/android/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * drivers/staging/android/ion/ion_carveout_heap.c + * ION Memory Allocator carveout heap helper * * Copyright (C) 2011 Google, Inc. */ diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index 159d72f5bc42..5a8917d9beac 100644 --- a/drivers/staging/android/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * drivers/staging/android/ion/ion_chunk_heap.c + * ION memory allocator chunk heap helper * * Copyright (C) 2012 Google, Inc. */ diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 3fafd013d80a..7b557dd5e78b 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * drivers/staging/android/ion/ion_cma_heap.c + * ION Memory Allocator CMA heap exporter * * Copyright (C) Linaro 2012 * Author: for ST-Ericsson. diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 31db510018a9..6ee0ac6e4be4 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * drivers/staging/android/ion/ion_heap.c + * ION Memory Allocator generic heap helpers * * Copyright (C) 2011 Google, Inc. */ diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 0d2a95957ee8..fd4995fb676e 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * drivers/staging/android/ion/ion_mem_pool.c + * ION Memory Allocator page pool helpers * * Copyright (C) 2011 Google, Inc. */ diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 0383f7548d48..643b32099488 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * drivers/staging/android/ion/ion_system_heap.c + * ION Memory Allocator system heap exporter * * Copyright (C) 2011 Google, Inc. */ -- cgit v1.2.3 From 2fbe1707bae2ba9f5f4f5dc96a26797ff3353b1f Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:11 -0600 Subject: staging: android: ion: Remove empty ion_ioctl_dir() function This function is empty of real function and can be replaced with _IOC_DIR(). Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion-ioctl.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion-ioctl.c b/drivers/staging/android/ion/ion-ioctl.c index a8d3cc412fb9..b366f97a5728 100644 --- a/drivers/staging/android/ion/ion-ioctl.c +++ b/drivers/staging/android/ion/ion-ioctl.c @@ -31,23 +31,11 @@ static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg) return 0; } -/* fix up the cases where the ioctl direction bits are incorrect */ -static unsigned int ion_ioctl_dir(unsigned int cmd) -{ - switch (cmd) { - default: - return _IOC_DIR(cmd); - } -} - long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret = 0; - unsigned int dir; union ion_ioctl_arg data; - dir = ion_ioctl_dir(cmd); - if (_IOC_SIZE(cmd) > sizeof(data)) return -EINVAL; @@ -65,7 +53,7 @@ long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return ret; } - if (!(dir & _IOC_WRITE)) + if (!(_IOC_DIR(cmd) & _IOC_WRITE)) memset(&data, 0, sizeof(data)); switch (cmd) { @@ -90,7 +78,7 @@ long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return -ENOTTY; } - if (dir & _IOC_READ) { + if (_IOC_DIR(cmd) & _IOC_READ) { if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) return -EFAULT; } -- cgit v1.2.3 From 4514e79e5a6b2aa846b0b771270a8b655ef5001d Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:12 -0600 Subject: staging: android: ion: Merge ion-ioctl.c into ion.c The file ion-ioctl.c is now much to small and tightly integrated with the main ion.c file to justify keeping it separate. Merge this file. Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/Makefile | 2 +- drivers/staging/android/ion/ion-ioctl.c | 86 --------------------------------- drivers/staging/android/ion/ion.c | 79 +++++++++++++++++++++++++++++- drivers/staging/android/ion/ion.h | 8 --- 4 files changed, 78 insertions(+), 97 deletions(-) delete mode 100644 drivers/staging/android/ion/ion-ioctl.c (limited to 'drivers') diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index bb30bf8774a0..17f3a7569e3d 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_ION) += ion.o ion-ioctl.o ion_heap.o +obj-$(CONFIG_ION) += ion.o ion_heap.o obj-$(CONFIG_ION_SYSTEM_HEAP) += ion_system_heap.o ion_page_pool.o obj-$(CONFIG_ION_CARVEOUT_HEAP) += ion_carveout_heap.o obj-$(CONFIG_ION_CHUNK_HEAP) += ion_chunk_heap.o diff --git a/drivers/staging/android/ion/ion-ioctl.c b/drivers/staging/android/ion/ion-ioctl.c deleted file mode 100644 index b366f97a5728..000000000000 --- a/drivers/staging/android/ion/ion-ioctl.c +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2011 Google, Inc. - */ - -#include -#include -#include -#include - -#include "ion.h" - -union ion_ioctl_arg { - struct ion_allocation_data allocation; - struct ion_heap_query query; -}; - -static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg) -{ - switch (cmd) { - case ION_IOC_HEAP_QUERY: - if (arg->query.reserved0 || - arg->query.reserved1 || - arg->query.reserved2) - return -EINVAL; - break; - default: - break; - } - - return 0; -} - -long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - int ret = 0; - union ion_ioctl_arg data; - - if (_IOC_SIZE(cmd) > sizeof(data)) - return -EINVAL; - - /* - * The copy_from_user is unconditional here for both read and write - * to do the validate. If there is no write for the ioctl, the - * buffer is cleared - */ - if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) - return -EFAULT; - - ret = validate_ioctl_arg(cmd, &data); - if (ret) { - pr_warn_once("%s: ioctl validate failed\n", __func__); - return ret; - } - - if (!(_IOC_DIR(cmd) & _IOC_WRITE)) - memset(&data, 0, sizeof(data)); - - switch (cmd) { - case ION_IOC_ALLOC: - { - int fd; - - fd = ion_alloc(data.allocation.len, - data.allocation.heap_id_mask, - data.allocation.flags); - if (fd < 0) - return fd; - - data.allocation.fd = fd; - - break; - } - case ION_IOC_HEAP_QUERY: - ret = ion_query_heaps(&data.query); - break; - default: - return -ENOTTY; - } - - if (_IOC_DIR(cmd) & _IOC_READ) { - if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) - return -EFAULT; - } - return ret; -} diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index de1ca5e26a4a..2d6d8c0994b2 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -390,7 +390,7 @@ static const struct dma_buf_ops dma_buf_ops = { .unmap = ion_dma_buf_kunmap, }; -int ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags) +static int ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags) { struct ion_device *dev = internal_dev; struct ion_buffer *buffer = NULL; @@ -447,7 +447,7 @@ int ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags) return fd; } -int ion_query_heaps(struct ion_heap_query *query) +static int ion_query_heaps(struct ion_heap_query *query) { struct ion_device *dev = internal_dev; struct ion_heap_data __user *buffer = u64_to_user_ptr(query->heaps); @@ -492,6 +492,81 @@ out: return ret; } +union ion_ioctl_arg { + struct ion_allocation_data allocation; + struct ion_heap_query query; +}; + +static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg) +{ + switch (cmd) { + case ION_IOC_HEAP_QUERY: + if (arg->query.reserved0 || + arg->query.reserved1 || + arg->query.reserved2) + return -EINVAL; + break; + default: + break; + } + + return 0; +} + +static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + union ion_ioctl_arg data; + + if (_IOC_SIZE(cmd) > sizeof(data)) + return -EINVAL; + + /* + * The copy_from_user is unconditional here for both read and write + * to do the validate. If there is no write for the ioctl, the + * buffer is cleared + */ + if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) + return -EFAULT; + + ret = validate_ioctl_arg(cmd, &data); + if (ret) { + pr_warn_once("%s: ioctl validate failed\n", __func__); + return ret; + } + + if (!(_IOC_DIR(cmd) & _IOC_WRITE)) + memset(&data, 0, sizeof(data)); + + switch (cmd) { + case ION_IOC_ALLOC: + { + int fd; + + fd = ion_alloc(data.allocation.len, + data.allocation.heap_id_mask, + data.allocation.flags); + if (fd < 0) + return fd; + + data.allocation.fd = fd; + + break; + } + case ION_IOC_HEAP_QUERY: + ret = ion_query_heaps(&data.query); + break; + default: + return -ENOTTY; + } + + if (_IOC_DIR(cmd) & _IOC_READ) { + if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) + return -EFAULT; + } + return ret; +} + static const struct file_operations ion_fops = { .owner = THIS_MODULE, .unlocked_ioctl = ion_ioctl, diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index ff455fdde1a8..084f246dcfc9 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -205,10 +205,6 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, int ion_heap_buffer_zero(struct ion_buffer *buffer); int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot); -int ion_alloc(size_t len, - unsigned int heap_id_mask, - unsigned int flags); - /** * ion_heap_init_shrinker * @heap: the heap @@ -330,8 +326,4 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page); int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, int nr_to_scan); -long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); - -int ion_query_heaps(struct ion_heap_query *query); - #endif /* _ION_H */ -- cgit v1.2.3 From 6e42d12ce0dac1834767c2128444935b3a4f3322 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:13 -0600 Subject: staging: android: ion: Remove leftover comment Since we use CMA APIs directly there is no device nor private heaps data, drop this comment. Fixes: 204f672255c2 ("staging: android: ion: Use CMA APIs directly") Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_cma_heap.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 7b557dd5e78b..bf65e67ef9d8 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -111,10 +111,6 @@ static struct ion_heap *__ion_cma_heap_create(struct cma *cma) return ERR_PTR(-ENOMEM); cma_heap->heap.ops = &ion_cma_ops; - /* - * get device from private heaps data, later it will be - * used to make the link with reserved CMA memory - */ cma_heap->cma = cma; cma_heap->heap.type = ION_HEAP_TYPE_DMA; return &cma_heap->heap; -- cgit v1.2.3 From c72f4e31c8a3c31bfdf4a1cbc595bb10d624c206 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:14 -0600 Subject: staging: android: ion: Remove struct ion_platform_heap Now that ION heap registration has been re-worked to not depend on board files or have a central heap register helper there is no need to have this data structure. Most of the fields are unused. Some heap creation helpers are still available that use this to define the a heap but only use 2 or 3 elements from this struct, just convert these to get supplied these values from the heap registrar directly. Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.h | 23 ----------------------- drivers/staging/android/ion/ion_carveout_heap.c | 12 ++++-------- drivers/staging/android/ion/ion_chunk_heap.c | 17 +++++++---------- 3 files changed, 11 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index 084f246dcfc9..2ef78c951a6b 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -21,29 +21,6 @@ #include "../uapi/ion.h" -/** - * struct ion_platform_heap - defines a heap in the given platform - * @type: type of the heap from ion_heap_type enum - * @id: unique identifier for heap. When allocating higher numb ers - * will be allocated from first. At allocation these are passed - * as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS. - * @name: used for debug purposes - * @base: base address of heap in physical memory if applicable - * @size: size of the heap in bytes if applicable - * @priv: private info passed from the board file - * - * Provided by the board file. - */ -struct ion_platform_heap { - enum ion_heap_type type; - unsigned int id; - const char *name; - phys_addr_t base; - size_t size; - phys_addr_t align; - void *priv; -}; - /** * struct ion_buffer - metadata for a particular buffer * @ref: reference count diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index 4a9f9c275654..891f5703220b 100644 --- a/drivers/staging/android/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -103,17 +103,14 @@ static struct ion_heap_ops carveout_heap_ops = { .unmap_kernel = ion_heap_unmap_kernel, }; -struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data) +struct ion_heap *ion_carveout_heap_create(phys_addr_t base, size_t size) { struct ion_carveout_heap *carveout_heap; int ret; struct page *page; - size_t size; - - page = pfn_to_page(PFN_DOWN(heap_data->base)); - size = heap_data->size; + page = pfn_to_page(PFN_DOWN(base)); ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL)); if (ret) return ERR_PTR(ret); @@ -127,9 +124,8 @@ struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data) kfree(carveout_heap); return ERR_PTR(-ENOMEM); } - carveout_heap->base = heap_data->base; - gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size, - -1); + carveout_heap->base = base; + gen_pool_add(carveout_heap->pool, carveout_heap->base, size, -1); carveout_heap->heap.ops = &carveout_heap_ops; carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT; carveout_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index 5a8917d9beac..c2321a047f0f 100644 --- a/drivers/staging/android/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -108,16 +108,13 @@ static struct ion_heap_ops chunk_heap_ops = { .unmap_kernel = ion_heap_unmap_kernel, }; -struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data) +struct ion_heap *ion_chunk_heap_create(phys_addr_t base, size_t size, size_t chunk_size) { struct ion_chunk_heap *chunk_heap; int ret; struct page *page; - size_t size; - - page = pfn_to_page(PFN_DOWN(heap_data->base)); - size = heap_data->size; + page = pfn_to_page(PFN_DOWN(base)); ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL)); if (ret) return ERR_PTR(ret); @@ -126,23 +123,23 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data) if (!chunk_heap) return ERR_PTR(-ENOMEM); - chunk_heap->chunk_size = (unsigned long)heap_data->priv; + chunk_heap->chunk_size = chunk_size; chunk_heap->pool = gen_pool_create(get_order(chunk_heap->chunk_size) + PAGE_SHIFT, -1); if (!chunk_heap->pool) { ret = -ENOMEM; goto error_gen_pool_create; } - chunk_heap->base = heap_data->base; - chunk_heap->size = heap_data->size; + chunk_heap->base = base; + chunk_heap->size = size; chunk_heap->allocated = 0; - gen_pool_add(chunk_heap->pool, chunk_heap->base, heap_data->size, -1); + gen_pool_add(chunk_heap->pool, chunk_heap->base, size, -1); chunk_heap->heap.ops = &chunk_heap_ops; chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK; chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; pr_debug("%s: base %pa size %zu\n", __func__, - &chunk_heap->base, heap_data->size); + &chunk_heap->base, size); return &chunk_heap->heap; -- cgit v1.2.3 From 4d5119f448a879692c5fc4b5e9ad7d7b71170fb5 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:15 -0600 Subject: staging: android: ion: Fixup some white-space issues Add white-space for easier reading and remove some where it does not belong. No functional changes, they just bug me.. Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_carveout_heap.c | 1 + drivers/staging/android/ion/ion_chunk_heap.c | 2 +- drivers/staging/android/ion/ion_heap.c | 6 ++++++ drivers/staging/android/ion/ion_system_heap.c | 6 +++++- 4 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index 891f5703220b..be80671df9c8 100644 --- a/drivers/staging/android/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -44,6 +44,7 @@ static void ion_carveout_free(struct ion_heap *heap, phys_addr_t addr, if (addr == ION_CARVEOUT_ALLOCATE_FAIL) return; + gen_pool_free(carveout_heap->pool, addr, size); } diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index c2321a047f0f..b82eac1c2d7a 100644 --- a/drivers/staging/android/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -4,6 +4,7 @@ * * Copyright (C) 2012 Google, Inc. */ + #include #include #include @@ -147,4 +148,3 @@ error_gen_pool_create: kfree(chunk_heap); return ERR_PTR(ret); } - diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 6ee0ac6e4be4..473b465724f1 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -14,6 +14,7 @@ #include #include #include + #include "ion.h" void *ion_heap_map_kernel(struct ion_heap *heap, @@ -92,6 +93,7 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, if (addr >= vma->vm_end) return 0; } + return 0; } @@ -254,6 +256,7 @@ int ion_heap_init_deferred_free(struct ion_heap *heap) return PTR_ERR_OR_ZERO(heap->task); } sched_setscheduler(heap->task, SCHED_IDLE, ¶m); + return 0; } @@ -265,8 +268,10 @@ static unsigned long ion_heap_shrink_count(struct shrinker *shrinker, int total = 0; total = ion_heap_freelist_size(heap) / PAGE_SIZE; + if (heap->ops->shrink) total += heap->ops->shrink(heap, sc->gfp_mask, 0); + return total; } @@ -295,6 +300,7 @@ static unsigned long ion_heap_shrink_scan(struct shrinker *shrinker, if (heap->ops->shrink) freed += heap->ops->shrink(heap, sc->gfp_mask, to_scan); + return freed; } diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 643b32099488..ec526a464db8 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -13,6 +13,7 @@ #include #include #include + #include "ion.h" #define NUM_ORDERS ARRAY_SIZE(orders) @@ -236,6 +237,7 @@ static int ion_system_heap_create_pools(struct ion_page_pool **pools) goto err_create_pool; pools[i] = pool; } + return 0; err_create_pool: @@ -274,6 +276,7 @@ static int ion_system_heap_create(void) heap->name = "ion_system_heap"; ion_device_add_heap(heap); + return 0; } device_initcall(ion_system_heap_create); @@ -355,6 +358,7 @@ static struct ion_heap *__ion_system_contig_heap_create(void) heap->ops = &kmalloc_ops; heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG; heap->name = "ion_system_contig_heap"; + return heap; } @@ -367,7 +371,7 @@ static int ion_system_contig_heap_create(void) return PTR_ERR(heap); ion_device_add_heap(heap); + return 0; } device_initcall(ion_system_contig_heap_create); - -- cgit v1.2.3 From 96d12a0d94097ba5797230b76c9bdc5c798750f3 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:16 -0600 Subject: staging: android: ion: Sync comment docs with struct ion_buffer This struct is no longer documented correctly, fix this. Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index 2ef78c951a6b..e291299fd35f 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -23,8 +23,8 @@ /** * struct ion_buffer - metadata for a particular buffer - * @ref: reference count * @node: node in the ion_device buffers tree + * @list: element in list of deferred freeable buffers * @dev: back pointer to the ion_device * @heap: back pointer to the heap the buffer came from * @flags: buffer specific flags @@ -35,7 +35,8 @@ * @lock: protects the buffers cnt fields * @kmap_cnt: number of times the buffer is mapped to the kernel * @vaddr: the kernel mapping if kmap_cnt is not zero - * @sg_table: the sg table for the buffer if dmap_cnt is not zero + * @sg_table: the sg table for the buffer + * @attachments: list of devices attached to this buffer */ struct ion_buffer { union { @@ -151,12 +152,16 @@ struct ion_heap { unsigned long flags; unsigned int id; const char *name; + + /* deferred free support */ struct shrinker shrinker; struct list_head free_list; size_t free_list_size; spinlock_t free_lock; wait_queue_head_t waitqueue; struct task_struct *task; + + /* heap statistics */ u64 num_of_buffers; u64 num_of_alloc_bytes; u64 alloc_bytes_wm; -- cgit v1.2.3 From 298783c27e291be5b38ad460eb909b46d353f9cd Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:17 -0600 Subject: staging: android: ion: Remove base from ion_carveout_heap The base address is not used anywhere and tracked by the pool allocator. No need to store this anymore. Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_carveout_heap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index be80671df9c8..ab9b72adca9c 100644 --- a/drivers/staging/android/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -20,7 +20,6 @@ struct ion_carveout_heap { struct ion_heap heap; struct gen_pool *pool; - phys_addr_t base; }; static phys_addr_t ion_carveout_allocate(struct ion_heap *heap, @@ -125,8 +124,7 @@ struct ion_heap *ion_carveout_heap_create(phys_addr_t base, size_t size) kfree(carveout_heap); return ERR_PTR(-ENOMEM); } - carveout_heap->base = base; - gen_pool_add(carveout_heap->pool, carveout_heap->base, size, -1); + gen_pool_add(carveout_heap->pool, base, size, -1); carveout_heap->heap.ops = &carveout_heap_ops; carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT; carveout_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; -- cgit v1.2.3 From dad407ae7df9448762e2e04b22fecf5ba5ce4e2d Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:18 -0600 Subject: staging: android: ion: Remove base from ion_chunk_heap The base address is not used anywhere and tracked by the pool allocator. No need to store this anymore. Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_chunk_heap.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index b82eac1c2d7a..899380beeee1 100644 --- a/drivers/staging/android/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -18,7 +18,6 @@ struct ion_chunk_heap { struct ion_heap heap; struct gen_pool *pool; - phys_addr_t base; unsigned long chunk_size; unsigned long size; unsigned long allocated; @@ -131,16 +130,14 @@ struct ion_heap *ion_chunk_heap_create(phys_addr_t base, size_t size, size_t chu ret = -ENOMEM; goto error_gen_pool_create; } - chunk_heap->base = base; chunk_heap->size = size; chunk_heap->allocated = 0; - gen_pool_add(chunk_heap->pool, chunk_heap->base, size, -1); + gen_pool_add(chunk_heap->pool, base, size, -1); chunk_heap->heap.ops = &chunk_heap_ops; chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK; chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; - pr_debug("%s: base %pa size %zu\n", __func__, - &chunk_heap->base, size); + pr_debug("%s: base %pa size %zu\n", __func__, &base, size); return &chunk_heap->heap; -- cgit v1.2.3 From 032ecb59aa3878d6d9984068d715ab9ce7e2e503 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 11 Jan 2019 12:05:19 -0600 Subject: staging: android: ion: Remove unused headers Various cleanups have removed the use of some headers in ION, remove these here. Signed-off-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.c | 3 --- drivers/staging/android/ion/ion_carveout_heap.c | 4 ++-- drivers/staging/android/ion/ion_chunk_heap.c | 3 +-- 3 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 2d6d8c0994b2..bba5f682bc25 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -5,7 +5,6 @@ * Copyright (C) 2011 Google, Inc. */ -#include #include #include #include @@ -14,10 +13,8 @@ #include #include #include -#include #include #include -#include #include #include #include diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index ab9b72adca9c..bb9d614767a2 100644 --- a/drivers/staging/android/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -4,7 +4,7 @@ * * Copyright (C) 2011 Google, Inc. */ -#include + #include #include #include @@ -12,7 +12,7 @@ #include #include #include -#include + #include "ion.h" #define ION_CARVEOUT_ALLOCATE_FAIL -1 diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index 899380beeee1..3cdde9c1a717 100644 --- a/drivers/staging/android/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -8,11 +8,10 @@ #include #include #include -#include #include #include #include -#include + #include "ion.h" struct ion_chunk_heap { -- cgit v1.2.3 From c0e6f5bf7676677af48abb8de706b2fb10191a27 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 16 Jan 2019 18:54:33 +0100 Subject: clk: meson: gxbb: claim clock controller input clock from DT Instead of relying on a fixed name for the xtal clock, claim the controller input clock trough DT. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190116175435.4990-2-jbrunet@baylibre.com --- drivers/clk/meson/gxbb.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 65f2599e5243..ecf9a8f6281c 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -16,6 +16,8 @@ #include "gxbb.h" #include "clk-regmap.h" +#define IN_PREFIX "ee-in-" + static DEFINE_SPINLOCK(meson_clk_lock); static const struct pll_params_table gxbb_gp0_pll_params_table[] = { @@ -118,7 +120,7 @@ static struct clk_regmap gxbb_fixed_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -148,7 +150,7 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_pre_mult", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -241,7 +243,7 @@ static struct clk_regmap gxl_hdmi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, /* * Display directly handle hdmi pll registers ATM, we need @@ -378,7 +380,7 @@ static struct clk_regmap gxbb_sys_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -439,7 +441,7 @@ static struct clk_regmap gxbb_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -491,7 +493,7 @@ static struct clk_regmap gxl_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -789,7 +791,7 @@ static struct clk_regmap gxbb_mpll2 = { static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { - "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", + IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", "fclk_div3", "fclk_div5" }; @@ -852,7 +854,7 @@ static struct clk_regmap gxbb_sar_adc_clk_sel = { .name = "sar_adc_clk_sel", .ops = &clk_regmap_mux_ops, /* NOTE: The datasheet doesn't list the parents for bit 10 */ - .parent_names = (const char *[]){ "xtal", "clk81", }, + .parent_names = (const char *[]){ IN_PREFIX "xtal", "clk81", }, .num_parents = 2, }, }; @@ -891,7 +893,7 @@ static struct clk_regmap gxbb_sar_adc_clk = { */ static const char * const gxbb_mali_0_1_parent_names[] = { - "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", + IN_PREFIX "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", "fclk_div5" }; @@ -1153,7 +1155,7 @@ static struct clk_regmap gxbb_32k_clk = { }; static const char * const gxbb_32k_clk_parent_names[] = { - "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" + IN_PREFIX "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" }; static struct clk_regmap gxbb_32k_clk_sel = { @@ -1172,7 +1174,7 @@ static struct clk_regmap gxbb_32k_clk_sel = { }; static const char * const gxbb_sd_emmc_clk0_parent_names[] = { - "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", + IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", /* * Following these parent clocks, we should also have had mpll2, mpll3 @@ -2138,7 +2140,7 @@ static struct clk_regmap gxbb_hdmi_tx = { /* HDMI Clocks */ static const char * const gxbb_hdmi_parent_names[] = { - "xtal", "fclk_div4", "fclk_div3", "fclk_div5" + IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5" }; static struct clk_regmap gxbb_hdmi_sel = { @@ -2285,7 +2287,7 @@ static struct clk_regmap gxbb_vdec_hevc = { static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; static const char * const gen_clk_parent_names[] = { - "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2", + IN_PREFIX "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2", "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", }; @@ -3085,6 +3087,7 @@ static const struct of_device_id clkc_match_table[] = { static int gxbb_clkc_probe(struct platform_device *pdev) { const struct clkc_data *clkc_data; + struct clk_hw *input; struct regmap *map; int ret, i; struct device *dev = &pdev->dev; @@ -3100,6 +3103,14 @@ static int gxbb_clkc_probe(struct platform_device *pdev) return PTR_ERR(map); } + input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); + if (IS_ERR(input)) { + ret = PTR_ERR(input); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get input clock"); + return ret; + } + /* Populate regmap for the common regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) gx_clk_regmaps[i]->map = map; -- cgit v1.2.3 From 6e73dac7078f13d7fd2ee0d59941c5425bcf8ed8 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 16 Jan 2019 18:54:34 +0100 Subject: clk: meson: axg: claim clock controller input clock from DT Instead of relying on a fixed name for the xtal clock, claim the controller input clock trough DT. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190116175435.4990-3-jbrunet@baylibre.com --- drivers/clk/meson/axg.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 792735d7e46e..1c6539eeee7c 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -20,6 +20,8 @@ #include "clkc.h" #include "axg.h" +#define IN_PREFIX "ee-in-" + static DEFINE_SPINLOCK(meson_clk_lock); static struct clk_regmap axg_fixed_pll_dco = { @@ -58,7 +60,7 @@ static struct clk_regmap axg_fixed_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -113,7 +115,7 @@ static struct clk_regmap axg_sys_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -214,7 +216,7 @@ static struct clk_regmap axg_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -283,7 +285,7 @@ static struct clk_regmap axg_hifi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hifi_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -701,7 +703,7 @@ static struct clk_regmap axg_pcie_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -803,7 +805,7 @@ static struct clk_regmap axg_pcie_cml_en1 = { static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { - "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", + IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", "fclk_div3", "fclk_div5" }; @@ -852,7 +854,7 @@ static struct clk_regmap axg_clk81 = { }; static const char * const axg_sd_emmc_clk0_parent_names[] = { - "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", + IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", /* * Following these parent clocks, we should also have had mpll2, mpll3 @@ -957,7 +959,7 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; static const char * const gen_clk_parent_names[] = { - "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3", + IN_PREFIX "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3", "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", }; @@ -1263,6 +1265,7 @@ static const struct of_device_id clkc_match_table[] = { static int axg_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct clk_hw *input; struct regmap *map; int ret, i; @@ -1273,6 +1276,14 @@ static int axg_clkc_probe(struct platform_device *pdev) return PTR_ERR(map); } + input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); + if (IS_ERR(input)) { + ret = PTR_ERR(input); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get input clock"); + return ret; + } + /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) axg_clk_regmaps[i]->map = map; -- cgit v1.2.3 From 439a6bb5bfe775f9aa18f267a54878e0ac7f3d49 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 16 Jan 2019 18:54:35 +0100 Subject: clk: meson: ao-clkc: claim clock controller input clocks from DT Instead of relying on a fixed names for the differents input clocks of the controller, get them through DT. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190116175435.4990-4-jbrunet@baylibre.com --- drivers/clk/meson/axg-aoclk.c | 22 +++++++++++++++++----- drivers/clk/meson/gxbb-aoclk.c | 25 +++++++++++++++++++------ drivers/clk/meson/meson-aoclk.c | 37 ++++++++++++++++++++++++++++++++++++- drivers/clk/meson/meson-aoclk.h | 12 ++++++++++-- 4 files changed, 82 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index 5f518be144ce..5701f5840b75 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -16,6 +16,8 @@ #include "meson-aoclk.h" #include "axg-aoclk.h" +#define IN_PREFIX "ao-in-" + /* * AO Configuration Clock registers offsets * Register offsets from the data sheet must be multiplied by 4. @@ -38,7 +40,7 @@ static struct clk_regmap axg_aoclk_##_name = { \ .hw.init = &(struct clk_init_data) { \ .name = "axg_ao_" #_name, \ .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ "clk81" }, \ + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ .num_parents = 1, \ .flags = CLK_IGNORE_UNUSED, \ }, \ @@ -60,7 +62,7 @@ static struct clk_regmap axg_aoclk_cts_oscin = { .hw.init = &(struct clk_init_data){ .name = "cts_oscin", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -167,7 +169,7 @@ static struct clk_regmap axg_aoclk_cts_rtc_oscin = { .name = "axg_ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "axg_ao_32k", - "axg_ext_32k" }, + IN_PREFIX "ext_32k-0" }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -183,7 +185,7 @@ static struct clk_regmap axg_aoclk_clk81 = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "clk81", + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", "axg_ao_cts_rtc_oscin"}, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, @@ -199,7 +201,8 @@ static struct clk_regmap axg_aoclk_saradc_mux = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_saradc_mux", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "xtal", "axg_ao_clk81" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal", + "axg_ao_clk81" }, .num_parents = 2, }, }; @@ -285,6 +288,12 @@ static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { .num = NR_CLKS, }; +static const struct meson_aoclk_input axg_aoclk_inputs[] = { + { .name = "xtal", .required = true }, + { .name = "mpeg-clk", .required = true }, + { .name = "ext-32k-0", .required = false }, +}; + static const struct meson_aoclk_data axg_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(axg_aoclk_reset), @@ -292,6 +301,9 @@ static const struct meson_aoclk_data axg_aoclkc_data = { .num_clks = ARRAY_SIZE(axg_aoclk_regmap), .clks = axg_aoclk_regmap, .hw_data = &axg_aoclk_onecell_data, + .inputs = axg_aoclk_inputs, + .num_inputs = ARRAY_SIZE(axg_aoclk_inputs), + .input_prefix = IN_PREFIX, }; static const struct of_device_id axg_aoclkc_match_table[] = { diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 5fa57b623b8f..510b6a7d2f18 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -9,6 +9,8 @@ #include "meson-aoclk.h" #include "gxbb-aoclk.h" +#define IN_PREFIX "ao-in-" + /* AO Configuration Clock registers offsets */ #define AO_RTI_PWR_CNTL_REG1 0x0c #define AO_RTI_PWR_CNTL_REG0 0x10 @@ -27,7 +29,7 @@ static struct clk_regmap _name##_ao = { \ .hw.init = &(struct clk_init_data) { \ .name = #_name "_ao", \ .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ "clk81" }, \ + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ .num_parents = 1, \ .flags = CLK_IGNORE_UNUSED, \ }, \ @@ -48,7 +50,7 @@ static struct clk_regmap ao_cts_oscin = { .hw.init = &(struct clk_init_data){ .name = "ao_cts_oscin", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -155,9 +157,9 @@ static struct clk_regmap ao_cts_rtc_oscin = { .hw.init = &(struct clk_init_data){ .name = "ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "ext_32k_0", - "ext_32k_1", - "ext_32k_2", + .parent_names = (const char *[]){ IN_PREFIX "ext-32k-0", + IN_PREFIX "ext-32k-1", + IN_PREFIX "ext-32k-2", "ao_32k" }, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, @@ -174,7 +176,7 @@ static struct clk_regmap ao_clk81 = { .hw.init = &(struct clk_init_data){ .name = "ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "clk81", + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", "ao_cts_rtc_oscin" }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, @@ -257,6 +259,14 @@ static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { .num = NR_CLKS, }; +static const struct meson_aoclk_input gxbb_aoclk_inputs[] = { + { .name = "xtal", .required = true, }, + { .name = "mpeg-clk", .required = true, }, + {. name = "ext-32k-0", .required = false, }, + {. name = "ext-32k-1", .required = false, }, + {. name = "ext-32k-2", .required = false, }, +}; + static const struct meson_aoclk_data gxbb_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(gxbb_aoclk_reset), @@ -264,6 +274,9 @@ static const struct meson_aoclk_data gxbb_aoclkc_data = { .num_clks = ARRAY_SIZE(gxbb_aoclk), .clks = gxbb_aoclk, .hw_data = &gxbb_aoclk_onecell_data, + .inputs = gxbb_aoclk_inputs, + .num_inputs = ARRAY_SIZE(gxbb_aoclk_inputs), + .input_prefix = IN_PREFIX, }; static const struct of_device_id gxbb_aoclkc_match_table[] = { diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index 258c8d259ea1..7b9d194ccc3b 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -14,7 +14,7 @@ #include #include #include -#include "clk-regmap.h" +#include #include "meson-aoclk.h" static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev, @@ -31,6 +31,37 @@ static const struct reset_control_ops meson_aoclk_reset_ops = { .reset = meson_aoclk_do_reset, }; +static int meson_aoclkc_register_inputs(struct device *dev, + struct meson_aoclk_data *data) +{ + struct clk_hw *hw; + char *str; + int i; + + for (i = 0; i < data->num_inputs; i++) { + const struct meson_aoclk_input *in = &data->inputs[i]; + + str = kasprintf(GFP_KERNEL, "%s%s", data->input_prefix, + in->name); + if (!str) + return -ENOMEM; + + hw = meson_clk_hw_register_input(dev, in->name, str, 0); + kfree(str); + + if (IS_ERR(hw)) { + if (!in->required && PTR_ERR(hw) == -ENOENT) + continue; + else if (PTR_ERR(hw) != -EPROBE_DEFER) + dev_err(dev, "failed to register input %s\n", + in->name); + return PTR_ERR(hw); + } + } + + return 0; +} + int meson_aoclkc_probe(struct platform_device *pdev) { struct meson_aoclk_reset_controller *rstc; @@ -53,6 +84,10 @@ int meson_aoclkc_probe(struct platform_device *pdev) return PTR_ERR(regmap); } + ret = meson_aoclkc_register_inputs(dev, data); + if (ret) + return ret; + /* Reset Controller */ rstc->data = data; rstc->regmap = regmap; diff --git a/drivers/clk/meson/meson-aoclk.h b/drivers/clk/meson/meson-aoclk.h index ab2819e88922..0758b35d4427 100644 --- a/drivers/clk/meson/meson-aoclk.h +++ b/drivers/clk/meson/meson-aoclk.h @@ -13,14 +13,22 @@ #include #include -#include "clk-regmap.h" +#include "clkc.h" + +struct meson_aoclk_input { + const char *name; + bool required; +}; struct meson_aoclk_data { const unsigned int reset_reg; const int num_reset; const unsigned int *reset; - int num_clks; + const int num_clks; struct clk_regmap **clks; + const int num_inputs; + const struct meson_aoclk_input *inputs; + const char *input_prefix; const struct clk_hw_onecell_data *hw_data; }; -- cgit v1.2.3 From c440eee1a7a1d0f2d5fc2ee6049e4a05da540f01 Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Wed, 16 Jan 2019 23:00:50 +0530 Subject: Staging: fbtft: Switch to the gpio descriptor interface This switches the fbtft driver to use GPIO descriptors rather than numerical gpios: Utilize the GPIO library's intrinsic handling of OF GPIOs and polarity. If the line is flagged active low, gpiolib will deal with this. Remove gpios from platform device structure. Neither assign statically numbers to gpios in platform device nor allow gpios to be parsed as module parameters. Signed-off-by: Nishad Kamdar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/fb_agm1264k-fl.c | 52 ++--- drivers/staging/fbtft/fb_bd663474.c | 6 +- drivers/staging/fbtft/fb_ili9163.c | 6 +- drivers/staging/fbtft/fb_ili9320.c | 2 +- drivers/staging/fbtft/fb_ili9325.c | 6 +- drivers/staging/fbtft/fb_ili9340.c | 2 +- drivers/staging/fbtft/fb_pcd8544.c | 4 +- drivers/staging/fbtft/fb_ra8875.c | 4 +- drivers/staging/fbtft/fb_s6d1121.c | 6 +- drivers/staging/fbtft/fb_sh1106.c | 2 +- drivers/staging/fbtft/fb_ssd1289.c | 6 +- drivers/staging/fbtft/fb_ssd1305.c | 4 +- drivers/staging/fbtft/fb_ssd1306.c | 4 +- drivers/staging/fbtft/fb_ssd1325.c | 6 +- drivers/staging/fbtft/fb_ssd1331.c | 10 +- drivers/staging/fbtft/fb_ssd1351.c | 2 +- drivers/staging/fbtft/fb_tls8204.c | 6 +- drivers/staging/fbtft/fb_uc1611.c | 4 +- drivers/staging/fbtft/fb_uc1701.c | 6 +- drivers/staging/fbtft/fb_upd161704.c | 6 +- drivers/staging/fbtft/fb_watterott.c | 4 +- drivers/staging/fbtft/fbtft-bus.c | 6 +- drivers/staging/fbtft/fbtft-core.c | 173 +++-------------- drivers/staging/fbtft/fbtft-io.c | 26 +-- drivers/staging/fbtft/fbtft.h | 21 +- drivers/staging/fbtft/fbtft_device.c | 344 +-------------------------------- drivers/staging/fbtft/flexfb.c | 12 +- 27 files changed, 143 insertions(+), 587 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c index f6f30f5bf15a..8f27bd8da17d 100644 --- a/drivers/staging/fbtft/fb_agm1264k-fl.c +++ b/drivers/staging/fbtft/fb_agm1264k-fl.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -79,14 +79,14 @@ static int init_display(struct fbtft_par *par) static void reset(struct fbtft_par *par) { - if (par->gpio.reset == -1) + if (!par->gpio.reset) return; dev_dbg(par->info->device, "%s()\n", __func__); - gpio_set_value(par->gpio.reset, 0); + gpiod_set_value(par->gpio.reset, 0); udelay(20); - gpio_set_value(par->gpio.reset, 1); + gpiod_set_value(par->gpio.reset, 1); mdelay(120); } @@ -98,30 +98,30 @@ static int verify_gpios(struct fbtft_par *par) dev_dbg(par->info->device, "%s()\n", __func__); - if (par->EPIN < 0) { + if (!par->EPIN) { dev_err(par->info->device, "Missing info about 'wr' (aka E) gpio. Aborting.\n"); return -EINVAL; } for (i = 0; i < 8; ++i) { - if (par->gpio.db[i] < 0) { + if (!par->gpio.db[i]) { dev_err(par->info->device, "Missing info about 'db[%i]' gpio. Aborting.\n", i); return -EINVAL; } } - if (par->CS0 < 0) { + if (!par->CS0) { dev_err(par->info->device, "Missing info about 'cs0' gpio. Aborting.\n"); return -EINVAL; } - if (par->CS1 < 0) { + if (!par->CS1) { dev_err(par->info->device, "Missing info about 'cs1' gpio. Aborting.\n"); return -EINVAL; } - if (par->RW < 0) { + if (!par->RW) { dev_err(par->info->device, "Missing info about 'rw' gpio. Aborting.\n"); return -EINVAL; @@ -139,22 +139,22 @@ request_gpios_match(struct fbtft_par *par, const struct fbtft_gpio *gpio) if (strcasecmp(gpio->name, "wr") == 0) { /* left ks0108 E pin */ par->EPIN = gpio->gpio; - return GPIOF_OUT_INIT_LOW; + return GPIOD_OUT_LOW; } else if (strcasecmp(gpio->name, "cs0") == 0) { /* left ks0108 controller pin */ par->CS0 = gpio->gpio; - return GPIOF_OUT_INIT_HIGH; + return GPIOD_OUT_HIGH; } else if (strcasecmp(gpio->name, "cs1") == 0) { /* right ks0108 controller pin */ par->CS1 = gpio->gpio; - return GPIOF_OUT_INIT_HIGH; + return GPIOD_OUT_HIGH; } /* if write (rw = 0) e(1->0) perform write */ /* if read (rw = 1) e(0->1) set data on D0-7*/ else if (strcasecmp(gpio->name, "rw") == 0) { par->RW = gpio->gpio; - return GPIOF_OUT_INIT_LOW; + return GPIOD_OUT_LOW; } return FBTFT_GPIO_NO_MATCH; @@ -194,15 +194,15 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...) /* select chip */ if (*buf) { /* cs1 */ - gpio_set_value(par->CS0, 1); - gpio_set_value(par->CS1, 0); + gpiod_set_value(par->CS0, 1); + gpiod_set_value(par->CS1, 0); } else { /* cs0 */ - gpio_set_value(par->CS0, 0); - gpio_set_value(par->CS1, 1); + gpiod_set_value(par->CS0, 0); + gpiod_set_value(par->CS1, 1); } - gpio_set_value(par->RS, 0); /* RS->0 (command mode) */ + gpiod_set_value(par->RS, 0); /* RS->0 (command mode) */ len--; if (len) { @@ -364,7 +364,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) write_reg(par, 0x00, (0x17 << 3) | (u8)y); /* write bitmap */ - gpio_set_value(par->RS, 1); /* RS->1 (data mode) */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ ret = par->fbtftops.write(par, buf, len); if (ret < 0) dev_err(par->info->device, @@ -387,7 +387,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) write_reg(par, 0x01, (0x17 << 3) | (u8)y); /* write bitmap */ - gpio_set_value(par->RS, 1); /* RS->1 (data mode) */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ par->fbtftops.write(par, buf, len); if (ret < 0) dev_err(par->info->device, @@ -397,8 +397,8 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) } kfree(convert_buf); - gpio_set_value(par->CS0, 1); - gpio_set_value(par->CS1, 1); + gpiod_set_value(par->CS0, 1); + gpiod_set_value(par->CS1, 1); return ret; } @@ -408,7 +408,7 @@ static int write(struct fbtft_par *par, void *buf, size_t len) fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, "%s(len=%d): ", __func__, len); - gpio_set_value(par->RW, 0); /* set write mode */ + gpiod_set_value(par->RW, 0); /* set write mode */ while (len--) { u8 i, data; @@ -417,12 +417,12 @@ static int write(struct fbtft_par *par, void *buf, size_t len) /* set data bus */ for (i = 0; i < 8; ++i) - gpio_set_value(par->gpio.db[i], data & (1 << i)); + gpiod_set_value(par->gpio.db[i], data & (1 << i)); /* set E */ - gpio_set_value(par->EPIN, 1); + gpiod_set_value(par->EPIN, 1); udelay(5); /* unset E - write */ - gpio_set_value(par->EPIN, 0); + gpiod_set_value(par->EPIN, 0); udelay(1); } diff --git a/drivers/staging/fbtft/fb_bd663474.c b/drivers/staging/fbtft/fb_bd663474.c index a58c514f4721..b6c6d66e4eb1 100644 --- a/drivers/staging/fbtft/fb_bd663474.c +++ b/drivers/staging/fbtft/fb_bd663474.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include "fbtft.h" @@ -24,8 +24,8 @@ static int init_display(struct fbtft_par *par) { - if (par->gpio.cs != -1) - gpio_set_value(par->gpio.cs, 0); /* Activate chip */ + if (!par->gpio.cs) + gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ par->fbtftops.reset(par); diff --git a/drivers/staging/fbtft/fb_ili9163.c b/drivers/staging/fbtft/fb_ili9163.c index 86e140244aab..d609a2b67db9 100644 --- a/drivers/staging/fbtft/fb_ili9163.c +++ b/drivers/staging/fbtft/fb_ili9163.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include