From 5a2b190cddb9aa69b9037f5b1fd1c2cc8a1d68b9 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 29 Jun 2016 19:28:01 +1000 Subject: [PATCH 0001/1587] HID: logitech-hidpp: add battery support for HID++ 2.0 devices If the 0x1000 Unified Battery Level Status feature exists, expose the battery level. The main drawback is that while a device is plugged in its battery level is 0. To avoid exposing that as 0% charge we make up a number based on the charging status. Signed-off-by: Peter Hutterer Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 238 ++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 2e2515a4c070..1ead9f697d8c 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -62,6 +62,8 @@ MODULE_PARM_DESC(disable_tap_to_click, #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22) #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) +#define HIDPP_QUIRK_HIDPP20_BATTERY BIT(25) +#define HIDPP_QUIRK_HIDPP10_BATTERY BIT(26) #define HIDPP_QUIRK_DELAYED_INIT (HIDPP_QUIRK_NO_HIDINPUT | \ HIDPP_QUIRK_CONNECT_EVENTS) @@ -110,6 +112,15 @@ struct hidpp_report { }; } __packed; +struct hidpp_battery { + u8 feature_index; + struct power_supply_desc desc; + struct power_supply *ps; + char name[64]; + int status; + int level; +}; + struct hidpp_device { struct hid_device *hid_dev; struct mutex send_mutex; @@ -128,8 +139,9 @@ struct hidpp_device { struct input_dev *delayed_input; unsigned long quirks; -}; + struct hidpp_battery battery; +}; /* HID++ 1.0 error codes */ #define HIDPP_ERROR 0x8f @@ -606,6 +618,222 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp) return name; } +/* -------------------------------------------------------------------------- */ +/* 0x1000: Battery level status */ +/* -------------------------------------------------------------------------- */ + +#define HIDPP_PAGE_BATTERY_LEVEL_STATUS 0x1000 + +#define CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS 0x00 +#define CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_CAPABILITY 0x10 + +#define EVENT_BATTERY_LEVEL_STATUS_BROADCAST 0x00 + +static int hidpp20_batterylevel_map_status_level(u8 data[3], int *level, + int *next_level) +{ + int status; + int level_override; + + *level = data[0]; + *next_level = data[1]; + + /* When discharging, we can rely on the device reported level. + * For all other states the device reports level 0 (unknown). Make up + * a number instead + */ + switch (data[2]) { + case 0: /* discharging (in use) */ + status = POWER_SUPPLY_STATUS_DISCHARGING; + level_override = 0; + break; + case 1: /* recharging */ + status = POWER_SUPPLY_STATUS_CHARGING; + level_override = 80; + break; + case 2: /* charge in final stage */ + status = POWER_SUPPLY_STATUS_CHARGING; + level_override = 90; + break; + case 3: /* charge complete */ + status = POWER_SUPPLY_STATUS_FULL; + level_override = 100; + break; + case 4: /* recharging below optimal speed */ + status = POWER_SUPPLY_STATUS_CHARGING; + level_override = 50; + break; + /* 5 = invalid battery type + 6 = thermal error + 7 = other charging error */ + default: + status = POWER_SUPPLY_STATUS_NOT_CHARGING; + level_override = 0; + break; + } + + if (level_override != 0 && *level == 0) + *level = level_override; + + return status; +} + +static int hidpp20_batterylevel_get_battery_level(struct hidpp_device *hidpp, + u8 feature_index, + int *status, + int *level, + int *next_level) +{ + struct hidpp_report response; + int ret; + u8 *params = (u8 *)response.fap.params; + + ret = hidpp_send_fap_command_sync(hidpp, feature_index, + CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS, + NULL, 0, &response); + if (ret > 0) { + hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", + __func__, ret); + return -EPROTO; + } + if (ret) + return ret; + + *status = hidpp20_batterylevel_map_status_level(params, level, + next_level); + + return 0; +} + +static int hidpp20_query_battery_info(struct hidpp_device *hidpp) +{ + u8 feature_type; + int ret; + int status, level, next_level; + + if (hidpp->battery.feature_index == 0) { + ret = hidpp_root_get_feature(hidpp, + HIDPP_PAGE_BATTERY_LEVEL_STATUS, + &hidpp->battery.feature_index, + &feature_type); + if (ret) + return ret; + } + + ret = hidpp20_batterylevel_get_battery_level(hidpp, + hidpp->battery.feature_index, + &status, &level, &next_level); + if (ret) + return ret; + + hidpp->battery.status = status; + hidpp->battery.level = level; + + return 0; +} + +static int hidpp20_battery_event(struct hidpp_device *hidpp, + u8 *data, int size) +{ + struct hidpp_report *report = (struct hidpp_report *)data; + int status, level, next_level; + bool changed; + + if (report->fap.feature_index != hidpp->battery.feature_index || + report->fap.funcindex_clientid != EVENT_BATTERY_LEVEL_STATUS_BROADCAST) + return 0; + + status = hidpp20_batterylevel_map_status_level(report->fap.params, + &level, &next_level); + + changed = level != hidpp->battery.level || + status != hidpp->battery.status; + + if (changed) { + hidpp->battery.level = level; + hidpp->battery.status = status; + if (hidpp->battery.ps) + power_supply_changed(hidpp->battery.ps); + } + + return 0; +} + +static enum power_supply_property hidpp_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CAPACITY, +}; + +static int hidpp_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct hidpp_device *hidpp = power_supply_get_drvdata(psy); + int ret = 0; + + switch(psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = hidpp->battery.status; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = hidpp->battery.level; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int hidpp20_initialize_battery(struct hidpp_device *hidpp) +{ + static atomic_t battery_no = ATOMIC_INIT(0); + struct power_supply_config cfg = { .drv_data = hidpp }; + struct power_supply_desc *desc = &hidpp->battery.desc; + struct hidpp_battery *battery; + unsigned long n; + int ret; + + ret = hidpp20_query_battery_info(hidpp); + if (ret) + return ret; + + battery = &hidpp->battery; + + n = atomic_inc_return(&battery_no) - 1; + desc->properties = hidpp_battery_props; + desc->num_properties = ARRAY_SIZE(hidpp_battery_props); + desc->get_property = hidpp_battery_get_property; + sprintf(battery->name, "hidpp_battery_%ld", n); + desc->name = battery->name; + desc->type = POWER_SUPPLY_TYPE_BATTERY; + desc->use_for_apm = 0; + + battery->ps = devm_power_supply_register(&hidpp->hid_dev->dev, + &battery->desc, + &cfg); + if (IS_ERR(battery->ps)) + return PTR_ERR(battery->ps); + + power_supply_powers(battery->ps, &hidpp->hid_dev->dev); + + return 0; +} + +static int hidpp_initialize_battery(struct hidpp_device *hidpp) +{ + int ret; + + if (hidpp->protocol_major >= 2) { + ret = hidpp20_initialize_battery(hidpp); + if (ret == 0) + hidpp->quirks |= HIDPP_QUIRK_HIDPP20_BATTERY; + } + + return ret; +} + /* -------------------------------------------------------------------------- */ /* 0x6010: Touchpad FW items */ /* -------------------------------------------------------------------------- */ @@ -2050,6 +2278,12 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, if (ret != 0) return ret; + if (hidpp->quirks & HIDPP_QUIRK_HIDPP20_BATTERY) { + ret = hidpp20_battery_event(hidpp, data, size); + if (ret != 0) + return ret; + } + if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) return wtp_raw_event(hdev, data, size); else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) @@ -2158,6 +2392,8 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) hidpp->protocol_major, hidpp->protocol_minor); } + hidpp_initialize_battery(hidpp); + if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)) /* if HID created the input nodes for us, we can stop now */ return; From 6bd4e65d521f924b9f17c6a285b5e1ea7a2bd4d4 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 29 Jun 2016 19:28:02 +1000 Subject: [PATCH 0002/1587] HID: logitech-hidpp: remove HIDPP_QUIRK_CONNECT_EVENTS Now that we can create battery power_supply sources, it's better to enable the connect_event callback unconditionally. Signed-off-by: Benjamin Tissoires Tested-by: Peter Hutterer Signed-off-by: Peter Hutterer Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 1ead9f697d8c..4eeb550617bf 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -58,15 +58,14 @@ MODULE_PARM_DESC(disable_tap_to_click, #define HIDPP_QUIRK_CLASS_G920 BIT(3) /* bits 2..20 are reserved for classes */ -#define HIDPP_QUIRK_CONNECT_EVENTS BIT(21) +/* #define HIDPP_QUIRK_CONNECT_EVENTS BIT(21) disabled */ #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22) #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) #define HIDPP_QUIRK_HIDPP20_BATTERY BIT(25) #define HIDPP_QUIRK_HIDPP10_BATTERY BIT(26) -#define HIDPP_QUIRK_DELAYED_INIT (HIDPP_QUIRK_NO_HIDINPUT | \ - HIDPP_QUIRK_CONNECT_EVENTS) +#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT /* * There are two hidpp protocols in use, the first version hidpp10 is known @@ -2230,8 +2229,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, if (unlikely(hidpp_report_is_connect_event(report))) { atomic_set(&hidpp->connected, !(report->rap.params[0] & (1 << 6))); - if ((hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) && - (schedule_work(&hidpp->work) == 0)) + if (schedule_work(&hidpp->work) == 0) dbg_hid("%s: connect event already queued\n", __func__); return 1; } @@ -2449,7 +2447,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) if (disable_raw_mode) { hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP; - hidpp->quirks &= ~HIDPP_QUIRK_CONNECT_EVENTS; hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT; } @@ -2535,12 +2532,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) } } - if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) { - /* Allow incoming packets */ - hid_device_io_start(hdev); + /* Allow incoming packets */ + hid_device_io_start(hdev); - hidpp_connect_event(hidpp); - } + hidpp_connect_event(hidpp); return ret; @@ -2593,7 +2588,7 @@ static const struct hid_device_id hidpp_devices[] = { { /* Keyboard logitech K400 */ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, USB_VENDOR_ID_LOGITECH, 0x4024), - .driver_data = HIDPP_QUIRK_CONNECT_EVENTS | HIDPP_QUIRK_CLASS_K400 }, + .driver_data = HIDPP_QUIRK_CLASS_K400 }, { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, From 351744aa0f0366f17118db58b011cd3b8678f923 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 11 Jul 2016 23:49:20 +0200 Subject: [PATCH 0003/1587] HID: logitech-hidpp: select CONFIG_POWER_SUPPLY A recent commit added barry support to this driver, but that causes a link failure when CONFIG_POWER_SUPPLY is not set: drivers/hid/built-in.o: In function `hidpp_battery_get_property': :(.text+0x1a834): undefined reference to `power_supply_get_drvdata' drivers/hid/built-in.o: In function `hidpp_raw_event': :(.text+0x1b10c): undefined reference to `power_supply_changed' drivers/hid/built-in.o: In function `hidpp_connect_event': :(.text+0x1bd88): undefined reference to `devm_power_supply_register' :(.text+0x1be30): undefined reference to `power_supply_powers' This adds a dependency, identically to the other HID drivers that need this. Signed-off-by: Arnd Bergmann Reviewed-by: Benjamin Tissoires Fixes: 5a2b190cddb9 ("HID: logitech-hidpp: add battery support for HID++ 2.0 devices") Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 5646ca4b95de..820bc73ac058 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -425,6 +425,7 @@ config HID_LOGITECH_DJ config HID_LOGITECH_HIDPP tristate "Logitech HID++ devices support" depends on HID_LOGITECH + select POWER_SUPPLY ---help--- Support for Logitech devices relyingon the HID++ Logitech specification From cc4a7ffe02c95f537541c91e9842e3710decae6e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 14 Dec 2016 12:20:55 +0100 Subject: [PATCH 0004/1587] spi: fsl-lpspi: Pre-initialize ret in fsl_lpspi_transfer_one_msg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With gcc 4.1.2: drivers/spi/spi-fsl-lpspi.c: In function ‘fsl_lpspi_transfer_one_msg’: drivers/spi/spi-fsl-lpspi.c:369: warning: ‘ret’ may be used uninitialized in this function If the message contains no transfers, the function will set the message's status to an uninitialized value, and will return that uninitialized value. While __spi_validate() should have been called in all paths leading to this, and thus have rejected such messages, we better pre-initialize ret to be safe for future modifications (spi_transfer_one_message() also does this). Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 52551f6d0c7d..2b93bc605b91 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -366,7 +366,7 @@ static int fsl_lpspi_transfer_one_msg(struct spi_master *master, struct spi_transfer *xfer; bool is_first_xfer = true; u32 temp; - int ret; + int ret = 0; msg->status = 0; msg->actual_length = 0; From 22c76326bff810d220fffdbaab949d09e2564067 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 9 Dec 2016 20:48:52 +0100 Subject: [PATCH 0005/1587] spi: spi-ath79: support multiple internal chip select lines Several devices with multiple flash chips use the internal chip select lines. Don't assume that chip select 1 and above are GPIO lines. Signed-off-by: Felix Fietkau Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index f369174fbd88..3e9b928b563b 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -78,14 +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 (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { /* SPI is normally active-low */ gpio_set_value(spi->cs_gpio, cs_high); } else { + u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); + if (cs_high) - sp->ioc_base |= AR71XX_SPI_IOC_CS0; + sp->ioc_base |= cs_bit; else - sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + sp->ioc_base &= ~cs_bit; ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } @@ -118,11 +120,8 @@ static int ath79_spi_setup_cs(struct spi_device *spi) struct ath79_spi *sp = ath79_spidev_to_sp(spi); int status; - if (spi->chip_select && !gpio_is_valid(spi->cs_gpio)) - return -EINVAL; - status = 0; - if (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { unsigned long flags; flags = GPIOF_DIR_OUT; @@ -134,10 +133,12 @@ static int ath79_spi_setup_cs(struct spi_device *spi) status = gpio_request_one(spi->cs_gpio, flags, dev_name(&spi->dev)); } else { + u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); + if (spi->mode & SPI_CS_HIGH) - sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + sp->ioc_base &= ~cs_bit; else - sp->ioc_base |= AR71XX_SPI_IOC_CS0; + sp->ioc_base |= cs_bit; ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } @@ -147,7 +148,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi) static void ath79_spi_cleanup_cs(struct spi_device *spi) { - if (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { gpio_free(spi->cs_gpio); } } From 91829a9a25cc931b76b01aa091a52e0edd649a72 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 9 Dec 2016 20:48:53 +0100 Subject: [PATCH 0006/1587] spi: spi-ath79: use gpio_set_value_cansleep for GPIO chip select Signed-off-by: Felix Fietkau Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 3e9b928b563b..b89cee11f418 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -80,7 +80,7 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active) if (gpio_is_valid(spi->cs_gpio)) { /* SPI is normally active-low */ - gpio_set_value(spi->cs_gpio, cs_high); + gpio_set_value_cansleep(spi->cs_gpio, cs_high); } else { u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); From 7c397d01e43493dd087f9cd926cd1fcf508a8019 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Wed, 14 Dec 2016 15:59:46 -0500 Subject: [PATCH 0007/1587] audit: Make AUDIT_KERNEL event conform to the specification The AUDIT_KERNEL event is not following name=value format. This causes some information to get lost. The event has been reformatted to follow the convention. Additionally the audit_enabled value was added for troubleshooting purposes. The following is an example of the new event: type=KERNEL audit(1480621249.833:1): state=initialized audit_enabled=0 res=1 Signed-off-by: Steve Grubb [PM: commit tweaks to make checkpatch.pl happy] Signed-off-by: Paul Moore --- kernel/audit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/audit.c b/kernel/audit.c index 41017685f9f2..57acf2541fdd 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1344,7 +1344,9 @@ static int __init audit_init(void) panic("audit: failed to start the kauditd thread (%d)\n", err); } - audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized"); + audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, + "state=initialized audit_enabled=%u res=1", + audit_enabled); return 0; } From 89670affa2a62c4868a2dd8a4195a1a2ec58cb27 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Wed, 14 Dec 2016 16:00:13 -0500 Subject: [PATCH 0008/1587] audit: Make AUDIT_ANOM_ABEND event normalized The audit event specification asks for certain fields to exist in all events. Running 'ausearch -m anom_abend -sv yes' returns no events. This patch adds the result field so that the AUDIT_ANOM_ABEND event conforms to the rules. Signed-off-by: Steve Grubb Signed-off-by: Paul Moore --- kernel/auditsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index f78cb1b3fa74..bb5f504592c6 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2411,7 +2411,7 @@ void audit_core_dumps(long signr) if (unlikely(!ab)) return; audit_log_task(ab); - audit_log_format(ab, " sig=%ld", signr); + audit_log_format(ab, " sig=%ld res=1", signr); audit_log_end(ab); } From 98cf9965c09fc3fe6d8bd9760dba1dec53e387cc Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 15 Dec 2016 14:43:49 +0000 Subject: [PATCH 0009/1587] regulator: arizona-micsupp: Use SoC component pin control functions The name of a codec pin can have an optional prefix string, which is defined by the SoC machine driver. The snd_soc_dapm_x_pin functions take the fully-specified name including the prefix and so the existing code would fail to find the pin if the audio machine driver had added a prefix. Switch to using the snd_soc_component_x_pin equivalent functions that take a specified SoC component and automatically add the name prefix to the provided pin name. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- drivers/regulator/arizona-micsupp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index fcb98dbda837..143946215e23 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -45,6 +45,7 @@ static void arizona_micsupp_check_cp(struct work_struct *work) struct arizona_micsupp *micsupp = container_of(work, struct arizona_micsupp, check_cp_work); struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm; + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct arizona *arizona = micsupp->arizona; struct regmap *regmap = arizona->regmap; unsigned int reg; @@ -59,9 +60,10 @@ static void arizona_micsupp_check_cp(struct work_struct *work) if (dapm) { if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) == ARIZONA_CPMIC_ENA) - snd_soc_dapm_force_enable_pin(dapm, "MICSUPP"); + snd_soc_component_force_enable_pin(component, + "MICSUPP"); else - snd_soc_dapm_disable_pin(dapm, "MICSUPP"); + snd_soc_component_disable_pin(component, "MICSUPP"); snd_soc_dapm_sync(dapm); } From c2e51ac3d0542440d5b2b8b52ff2ad00751af4da Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 12 Sep 2016 22:50:41 +0200 Subject: [PATCH 0010/1587] spi: core: Extract of_spi_parse_dt() Extract the parsing of SPI slave-specific properties into its own function, so it can be reused later for SPI slave controllers. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi.c | 60 ++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 656dd3e3220c..1861255866d7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1502,37 +1502,18 @@ err_init_queue: /*-------------------------------------------------------------------------*/ #if defined(CONFIG_OF) -static struct spi_device * -of_register_spi_device(struct spi_master *master, struct device_node *nc) +static int of_spi_parse_dt(struct spi_master *master, struct spi_device *spi, + struct device_node *nc) { - struct spi_device *spi; - int rc; u32 value; - - /* Alloc an spi_device */ - spi = spi_alloc_device(master); - if (!spi) { - dev_err(&master->dev, "spi_device alloc error for %s\n", - nc->full_name); - rc = -ENOMEM; - goto err_out; - } - - /* Select device driver */ - rc = of_modalias_node(nc, spi->modalias, - sizeof(spi->modalias)); - if (rc < 0) { - dev_err(&master->dev, "cannot find modalias for %s\n", - nc->full_name); - goto err_out; - } + int rc; /* Device address */ rc = of_property_read_u32(nc, "reg", &value); if (rc) { dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n", nc->full_name, rc); - goto err_out; + return rc; } spi->chip_select = value; @@ -1590,10 +1571,41 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc) if (rc) { dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n", nc->full_name, rc); - goto err_out; + return rc; } spi->max_speed_hz = value; + return 0; +} + +static struct spi_device * +of_register_spi_device(struct spi_master *master, struct device_node *nc) +{ + struct spi_device *spi; + int rc; + + /* Alloc an spi_device */ + spi = spi_alloc_device(master); + if (!spi) { + dev_err(&master->dev, "spi_device alloc error for %s\n", + nc->full_name); + rc = -ENOMEM; + goto err_out; + } + + /* Select device driver */ + rc = of_modalias_node(nc, spi->modalias, + sizeof(spi->modalias)); + if (rc < 0) { + dev_err(&master->dev, "cannot find modalias for %s\n", + nc->full_name); + goto err_out; + } + + rc = of_spi_parse_dt(master, spi, nc); + if (rc) + goto err_out; + /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.of_node = nc; From 14d37564fa3dc4e5d4c6828afcd26ac14e6796c5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 Dec 2016 08:02:03 -0600 Subject: [PATCH 0011/1587] GFS2: Fix reference to ERR_PTR in gfs2_glock_iter_next This patch fixes a place where function gfs2_glock_iter_next can reference an invalid error pointer. Signed-off-by: Dan Carpenter Signed-off-by: Bob Peterson --- fs/gfs2/glock.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 14cbf60167a7..2928f1209b67 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1802,16 +1802,18 @@ void gfs2_glock_exit(void) static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi) { - do { - gi->gl = rhashtable_walk_next(&gi->hti); + while ((gi->gl = rhashtable_walk_next(&gi->hti))) { if (IS_ERR(gi->gl)) { if (PTR_ERR(gi->gl) == -EAGAIN) continue; gi->gl = NULL; + return; } - /* Skip entries for other sb and dead entries */ - } while ((gi->gl) && ((gi->sdp != gi->gl->gl_name.ln_sbd) || - __lockref_is_dead(&gi->gl->gl_lockref))); + /* Skip entries for other sb and dead entries */ + if (gi->sdp == gi->gl->gl_name.ln_sbd && + !__lockref_is_dead(&gi->gl->gl_lockref)) + return; + } } static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos) From 0cc059abac0dc687dc714f3ec2c8d8a134132f56 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 16 Dec 2016 12:33:59 +0300 Subject: [PATCH 0012/1587] spi: armada-3700: Remove unnecessary condition We checked that "a3700_spi->wait_mask & cause" was set at the beginning of the function so we don't need to check again here. Signed-off-by: Dan Carpenter Acked-by: Romain Perier Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 4e921782652f..4e68f34957cc 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -340,8 +340,7 @@ static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id) spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, cause); /* Wake up the transfer */ - if (a3700_spi->wait_mask & cause) - complete(&a3700_spi->done); + complete(&a3700_spi->done); return IRQ_HANDLED; } From 23e291c2e4c84a40a4b3de8539dec95bfda214f1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 16 Dec 2016 16:59:16 -0800 Subject: [PATCH 0013/1587] spi: rockchip: support "sleep" pin configuration In the pattern of many other devices, support a system-sleep pin configuration. Signed-off-by: Brian Norris Reviewed-by: Douglas Anderson Tested-by: Caesar Wang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rockchip.txt | 7 +++++++ drivers/spi/spi-rockchip.c | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt b/Documentation/devicetree/bindings/spi/spi-rockchip.txt index d2ca153614f9..83da4931d832 100644 --- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt @@ -31,6 +31,10 @@ Optional Properties: - rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling Rx data (may need to be fine tuned for high capacitance lines). No delay (0) by default. +- pinctrl-names: Names for the pin configuration(s); may be "default" or + "sleep", where the "sleep" configuration may describe the state + the pins should be in during system suspend. See also + pinctrl/pinctrl-bindings.txt. Example: @@ -46,4 +50,7 @@ Example: interrupts = ; clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>; clock-names = "spiclk", "apb_pclk"; + pinctrl-0 = <&spi1_pins>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; }; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0f89c2169c24..acf31f36b898 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -843,6 +844,8 @@ static int rockchip_spi_suspend(struct device *dev) clk_disable_unprepare(rs->apb_pclk); } + pinctrl_pm_select_sleep_state(dev); + return ret; } @@ -852,6 +855,8 @@ static int rockchip_spi_resume(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct rockchip_spi *rs = spi_master_get_devdata(master); + pinctrl_pm_select_default_state(dev); + if (!pm_runtime_suspended(dev)) { ret = clk_prepare_enable(rs->apb_pclk); if (ret < 0) From 671a911bb9aea07360cb253e98acb4b7e6fbdd07 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 19 Dec 2016 22:40:25 +0800 Subject: [PATCH 0014/1587] regmap: use rb_entry() To make the code clearer, use rb_entry() instead of container_of() to deal with rbtree. Signed-off-by: Geliang Tang Signed-off-by: Mark Brown --- drivers/base/regmap/regcache-rbtree.c | 7 +++---- drivers/base/regmap/regmap.c | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index b11af3f2c1db..b1e9aae9a5d0 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -81,7 +81,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, node = rbtree_ctx->root.rb_node; while (node) { - rbnode = container_of(node, struct regcache_rbtree_node, node); + rbnode = rb_entry(node, struct regcache_rbtree_node, node); regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg, &top_reg); if (reg >= base_reg && reg <= top_reg) { @@ -108,8 +108,7 @@ static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root, parent = NULL; new = &root->rb_node; while (*new) { - rbnode_tmp = container_of(*new, struct regcache_rbtree_node, - node); + rbnode_tmp = rb_entry(*new, struct regcache_rbtree_node, node); /* base and top registers of the current rbnode */ regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp, &top_reg_tmp); @@ -152,7 +151,7 @@ static int rbtree_show(struct seq_file *s, void *ignored) for (node = rb_first(&rbtree_ctx->root); node != NULL; node = rb_next(node)) { - n = container_of(node, struct regcache_rbtree_node, node); + n = rb_entry(node, struct regcache_rbtree_node, node); mem_size += sizeof(*n); mem_size += (n->blklen * map->cache_word_size); mem_size += BITS_TO_LONGS(n->blklen) * sizeof(long); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ae63bb0875ea..900a319f626e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -459,7 +459,7 @@ static bool _regmap_range_add(struct regmap *map, while (*new) { struct regmap_range_node *this = - container_of(*new, struct regmap_range_node, node); + rb_entry(*new, struct regmap_range_node, node); parent = *new; if (data->range_max < this->range_min) @@ -483,7 +483,7 @@ static struct regmap_range_node *_regmap_range_lookup(struct regmap *map, while (node) { struct regmap_range_node *this = - container_of(node, struct regmap_range_node, node); + rb_entry(node, struct regmap_range_node, node); if (reg < this->range_min) node = node->rb_left; From 9e35d6fa825c02bdd00c24cb32299355702130bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Thu, 17 Nov 2016 16:09:19 +0100 Subject: [PATCH 0015/1587] pinctrl: sh-pfc: r8a7796: Add drive strength support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define the drive strength registers for the R8A7796. Add pins which are not part of a GPIO bank nor can be muxed between different functions but which still allow for their drive-strength to be configured. Signed-off-by: Niklas Söderlund Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7796.c | 359 ++++++++++++++++++++++++++- 1 file changed, 347 insertions(+), 12 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 7e16545a2c3c..21599ad891f0 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -19,19 +19,21 @@ #include "core.h" #include "sh_pfc.h" +#define CFG_FLAGS SH_PFC_PIN_CFG_DRIVE_STRENGTH + #define CPU_ALL_PORT(fn, sfx) \ - PORT_GP_16(0, fn, sfx), \ - PORT_GP_29(1, fn, sfx), \ - PORT_GP_15(2, fn, sfx), \ - PORT_GP_CFG_12(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ - PORT_GP_1(3, 12, fn, sfx), \ - PORT_GP_1(3, 13, fn, sfx), \ - PORT_GP_1(3, 14, fn, sfx), \ - PORT_GP_1(3, 15, fn, sfx), \ - PORT_GP_CFG_18(4, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ - PORT_GP_26(5, fn, sfx), \ - PORT_GP_32(6, fn, sfx), \ - PORT_GP_4(7, fn, sfx) + PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ + PORT_GP_CFG_1(3, 12, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(3, 13, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(3, 14, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(3, 15, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ + PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) /* * F_() : just information * FM() : macro for FN_xxx / xxx_MARK @@ -541,6 +543,23 @@ MOD_SEL0_2 MOD_SEL1_2 \ MOD_SEL1_1 \ MOD_SEL1_0 MOD_SEL2_0 +/* + * These pins are not able to be muxed but have other properties + * that can be set, such as drive-strength or pull-up/pull-down enable. + */ +#define PINMUX_STATIC \ + FM(QSPI0_SPCLK) FM(QSPI0_SSL) FM(QSPI0_MOSI_IO0) FM(QSPI0_MISO_IO1) \ + FM(QSPI0_IO2) FM(QSPI0_IO3) \ + FM(QSPI1_SPCLK) FM(QSPI1_SSL) FM(QSPI1_MOSI_IO0) FM(QSPI1_MISO_IO1) \ + FM(QSPI1_IO2) FM(QSPI1_IO3) \ + FM(RPC_INT) FM(RPC_WP) FM(RPC_RESET) \ + FM(AVB_TX_CTL) FM(AVB_TXC) FM(AVB_TD0) FM(AVB_TD1) FM(AVB_TD2) FM(AVB_TD3) \ + FM(AVB_RX_CTL) FM(AVB_RXC) FM(AVB_RD0) FM(AVB_RD1) FM(AVB_RD2) FM(AVB_RD3) \ + FM(AVB_TXCREFCLK) FM(AVB_MDIO) \ + FM(PRESETOUT) \ + FM(DU_DOTCLKIN0) FM(DU_DOTCLKIN1) FM(DU_DOTCLKIN2) \ + FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) + enum { PINMUX_RESERVED = 0, @@ -565,6 +584,7 @@ enum { PINMUX_GPSR PINMUX_IPSR PINMUX_MOD_SELS + PINMUX_STATIC PINMUX_MARK_END, #undef F_ #undef FM @@ -1484,10 +1504,76 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_NOGP(0, I2C_SEL_0_1), PINMUX_IPSR_NOGP(0, I2C_SEL_3_1), PINMUX_IPSR_NOGP(0, I2C_SEL_5_1), + +/* + * Static pins can not be muxed between different functions but + * still needs a mark entry in the pinmux list. Add each static + * pin to the list without an associated function. The sh-pfc + * core will do the right thing and skip trying to mux then pin + * while still applying configuration to it + */ +#define FM(x) PINMUX_DATA(x##_MARK, 0), + PINMUX_STATIC +#undef FM }; +/* + * R8A7796 has 8 banks with 32 GPIOs in each => 256 GPIOs. + * Physical layout rows: A - AW, cols: 1 - 39. + */ +#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r)) +#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300) +#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c) + static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), + + /* + * Pins not associated with a GPIO port. + * + * The pin positions are different between different r8a7796 + * packages, all that is needed for the pfc driver is a unique + * number for each pin. To this end use the pin layout from + * R-Car M3SiP to calculate a unique number for each pin. + */ + SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), }; /* - EtherAVB --------------------------------------------------------------- */ @@ -3187,6 +3273,254 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { { }, }; +static const struct pinmux_drive_reg pinmux_drive_regs[] = { + { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) { + { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */ + { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */ + { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */ + { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */ + { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */ + { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */ + { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */ + { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) { + { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */ + { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */ + { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */ + { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */ + { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */ + { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */ + { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */ + { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) { + { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */ + { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */ + { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */ + { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */ + { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */ + { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */ + { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */ + { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) { + { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */ + { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */ + { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */ + { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */ + { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */ + { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ + { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ + { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) { + { RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */ + { RCAR_GP_PIN(2, 13), 24, 3 }, /* AVB_AVTP_MATCH */ + { RCAR_GP_PIN(2, 14), 20, 3 }, /* AVB_AVTP_CAPTURE */ + { RCAR_GP_PIN(2, 0), 16, 3 }, /* IRQ0 */ + { RCAR_GP_PIN(2, 1), 12, 3 }, /* IRQ1 */ + { RCAR_GP_PIN(2, 2), 8, 3 }, /* IRQ2 */ + { RCAR_GP_PIN(2, 3), 4, 3 }, /* IRQ3 */ + { RCAR_GP_PIN(2, 4), 0, 3 }, /* IRQ4 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL5", 0xe6060314) { + { RCAR_GP_PIN(2, 5), 28, 3 }, /* IRQ5 */ + { RCAR_GP_PIN(2, 6), 24, 3 }, /* PWM0 */ + { RCAR_GP_PIN(2, 7), 20, 3 }, /* PWM1 */ + { RCAR_GP_PIN(2, 8), 16, 3 }, /* PWM2 */ + { RCAR_GP_PIN(1, 0), 12, 3 }, /* A0 */ + { RCAR_GP_PIN(1, 1), 8, 3 }, /* A1 */ + { RCAR_GP_PIN(1, 2), 4, 3 }, /* A2 */ + { RCAR_GP_PIN(1, 3), 0, 3 }, /* A3 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL6", 0xe6060318) { + { RCAR_GP_PIN(1, 4), 28, 3 }, /* A4 */ + { RCAR_GP_PIN(1, 5), 24, 3 }, /* A5 */ + { RCAR_GP_PIN(1, 6), 20, 3 }, /* A6 */ + { RCAR_GP_PIN(1, 7), 16, 3 }, /* A7 */ + { RCAR_GP_PIN(1, 8), 12, 3 }, /* A8 */ + { RCAR_GP_PIN(1, 9), 8, 3 }, /* A9 */ + { RCAR_GP_PIN(1, 10), 4, 3 }, /* A10 */ + { RCAR_GP_PIN(1, 11), 0, 3 }, /* A11 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL7", 0xe606031c) { + { RCAR_GP_PIN(1, 12), 28, 3 }, /* A12 */ + { RCAR_GP_PIN(1, 13), 24, 3 }, /* A13 */ + { RCAR_GP_PIN(1, 14), 20, 3 }, /* A14 */ + { RCAR_GP_PIN(1, 15), 16, 3 }, /* A15 */ + { RCAR_GP_PIN(1, 16), 12, 3 }, /* A16 */ + { RCAR_GP_PIN(1, 17), 8, 3 }, /* A17 */ + { RCAR_GP_PIN(1, 18), 4, 3 }, /* A18 */ + { RCAR_GP_PIN(1, 19), 0, 3 }, /* A19 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL8", 0xe6060320) { + { RCAR_GP_PIN(1, 28), 28, 3 }, /* CLKOUT */ + { RCAR_GP_PIN(1, 20), 24, 3 }, /* CS0 */ + { RCAR_GP_PIN(1, 21), 20, 3 }, /* CS1_A26 */ + { RCAR_GP_PIN(1, 22), 16, 3 }, /* BS */ + { RCAR_GP_PIN(1, 23), 12, 3 }, /* RD */ + { RCAR_GP_PIN(1, 24), 8, 3 }, /* RD_WR */ + { RCAR_GP_PIN(1, 25), 4, 3 }, /* WE0 */ + { RCAR_GP_PIN(1, 26), 0, 3 }, /* WE1 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) { + { RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */ + { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */ + { RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */ + { RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */ + { RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */ + { RCAR_GP_PIN(0, 3), 8, 3 }, /* D3 */ + { RCAR_GP_PIN(0, 4), 4, 3 }, /* D4 */ + { RCAR_GP_PIN(0, 5), 0, 3 }, /* D5 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL10", 0xe6060328) { + { RCAR_GP_PIN(0, 6), 28, 3 }, /* D6 */ + { RCAR_GP_PIN(0, 7), 24, 3 }, /* D7 */ + { RCAR_GP_PIN(0, 8), 20, 3 }, /* D8 */ + { RCAR_GP_PIN(0, 9), 16, 3 }, /* D9 */ + { RCAR_GP_PIN(0, 10), 12, 3 }, /* D10 */ + { RCAR_GP_PIN(0, 11), 8, 3 }, /* D11 */ + { RCAR_GP_PIN(0, 12), 4, 3 }, /* D12 */ + { RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) { + { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ + { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ + { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ + { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ + { RCAR_GP_PIN(7, 2), 12, 3 }, /* HDMI0_CEC */ + { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ + { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */ + { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) { + { PIN_A_NUMBER('R', 8), 28, 2 }, /* DU_DOTCLKIN2 */ + { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST */ + { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) { + { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */ + { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */ + { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ + { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) { + { RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */ + { RCAR_GP_PIN(3, 7), 24, 3 }, /* SD1_CMD */ + { RCAR_GP_PIN(3, 8), 20, 3 }, /* SD1_DAT0 */ + { RCAR_GP_PIN(3, 9), 16, 3 }, /* SD1_DAT1 */ + { RCAR_GP_PIN(3, 10), 12, 3 }, /* SD1_DAT2 */ + { RCAR_GP_PIN(3, 11), 8, 3 }, /* SD1_DAT3 */ + { RCAR_GP_PIN(4, 0), 4, 3 }, /* SD2_CLK */ + { RCAR_GP_PIN(4, 1), 0, 3 }, /* SD2_CMD */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL15", 0xe606033c) { + { RCAR_GP_PIN(4, 2), 28, 3 }, /* SD2_DAT0 */ + { RCAR_GP_PIN(4, 3), 24, 3 }, /* SD2_DAT1 */ + { RCAR_GP_PIN(4, 4), 20, 3 }, /* SD2_DAT2 */ + { RCAR_GP_PIN(4, 5), 16, 3 }, /* SD2_DAT3 */ + { RCAR_GP_PIN(4, 6), 12, 3 }, /* SD2_DS */ + { RCAR_GP_PIN(4, 7), 8, 3 }, /* SD3_CLK */ + { RCAR_GP_PIN(4, 8), 4, 3 }, /* SD3_CMD */ + { RCAR_GP_PIN(4, 9), 0, 3 }, /* SD3_DAT0 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL16", 0xe6060340) { + { RCAR_GP_PIN(4, 10), 28, 3 }, /* SD3_DAT1 */ + { RCAR_GP_PIN(4, 11), 24, 3 }, /* SD3_DAT2 */ + { RCAR_GP_PIN(4, 12), 20, 3 }, /* SD3_DAT3 */ + { RCAR_GP_PIN(4, 13), 16, 3 }, /* SD3_DAT4 */ + { RCAR_GP_PIN(4, 14), 12, 3 }, /* SD3_DAT5 */ + { RCAR_GP_PIN(4, 15), 8, 3 }, /* SD3_DAT6 */ + { RCAR_GP_PIN(4, 16), 4, 3 }, /* SD3_DAT7 */ + { RCAR_GP_PIN(4, 17), 0, 3 }, /* SD3_DS */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL17", 0xe6060344) { + { RCAR_GP_PIN(3, 12), 28, 3 }, /* SD0_CD */ + { RCAR_GP_PIN(3, 13), 24, 3 }, /* SD0_WP */ + { RCAR_GP_PIN(3, 14), 20, 3 }, /* SD1_CD */ + { RCAR_GP_PIN(3, 15), 16, 3 }, /* SD1_WP */ + { RCAR_GP_PIN(5, 0), 12, 3 }, /* SCK0 */ + { RCAR_GP_PIN(5, 1), 8, 3 }, /* RX0 */ + { RCAR_GP_PIN(5, 2), 4, 3 }, /* TX0 */ + { RCAR_GP_PIN(5, 3), 0, 3 }, /* CTS0 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL18", 0xe6060348) { + { RCAR_GP_PIN(5, 4), 28, 3 }, /* RTS0_TANS */ + { RCAR_GP_PIN(5, 5), 24, 3 }, /* RX1 */ + { RCAR_GP_PIN(5, 6), 20, 3 }, /* TX1 */ + { RCAR_GP_PIN(5, 7), 16, 3 }, /* CTS1 */ + { RCAR_GP_PIN(5, 8), 12, 3 }, /* RTS1_TANS */ + { RCAR_GP_PIN(5, 9), 8, 3 }, /* SCK2 */ + { RCAR_GP_PIN(5, 10), 4, 3 }, /* TX2 */ + { RCAR_GP_PIN(5, 11), 0, 3 }, /* RX2 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL19", 0xe606034c) { + { RCAR_GP_PIN(5, 12), 28, 3 }, /* HSCK0 */ + { RCAR_GP_PIN(5, 13), 24, 3 }, /* HRX0 */ + { RCAR_GP_PIN(5, 14), 20, 3 }, /* HTX0 */ + { RCAR_GP_PIN(5, 15), 16, 3 }, /* HCTS0 */ + { RCAR_GP_PIN(5, 16), 12, 3 }, /* HRTS0 */ + { RCAR_GP_PIN(5, 17), 8, 3 }, /* MSIOF0_SCK */ + { RCAR_GP_PIN(5, 18), 4, 3 }, /* MSIOF0_SYNC */ + { RCAR_GP_PIN(5, 19), 0, 3 }, /* MSIOF0_SS1 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL20", 0xe6060350) { + { RCAR_GP_PIN(5, 20), 28, 3 }, /* MSIOF0_TXD */ + { RCAR_GP_PIN(5, 21), 24, 3 }, /* MSIOF0_SS2 */ + { RCAR_GP_PIN(5, 22), 20, 3 }, /* MSIOF0_RXD */ + { RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */ + { RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */ + { RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */ + { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */ + { RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) { + { RCAR_GP_PIN(6, 1), 28, 3 }, /* SSI_WS01239 */ + { RCAR_GP_PIN(6, 2), 24, 3 }, /* SSI_SDATA0 */ + { RCAR_GP_PIN(6, 3), 20, 3 }, /* SSI_SDATA1 */ + { RCAR_GP_PIN(6, 4), 16, 3 }, /* SSI_SDATA2 */ + { RCAR_GP_PIN(6, 5), 12, 3 }, /* SSI_SCK34 */ + { RCAR_GP_PIN(6, 6), 8, 3 }, /* SSI_WS34 */ + { RCAR_GP_PIN(6, 7), 4, 3 }, /* SSI_SDATA3 */ + { RCAR_GP_PIN(6, 8), 0, 3 }, /* SSI_SCK4 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL22", 0xe6060358) { + { RCAR_GP_PIN(6, 9), 28, 3 }, /* SSI_WS4 */ + { RCAR_GP_PIN(6, 10), 24, 3 }, /* SSI_SDATA4 */ + { RCAR_GP_PIN(6, 11), 20, 3 }, /* SSI_SCK5 */ + { RCAR_GP_PIN(6, 12), 16, 3 }, /* SSI_WS5 */ + { RCAR_GP_PIN(6, 13), 12, 3 }, /* SSI_SDATA5 */ + { RCAR_GP_PIN(6, 14), 8, 3 }, /* SSI_SCK6 */ + { RCAR_GP_PIN(6, 15), 4, 3 }, /* SSI_WS6 */ + { RCAR_GP_PIN(6, 16), 0, 3 }, /* SSI_SDATA6 */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL23", 0xe606035c) { + { RCAR_GP_PIN(6, 17), 28, 3 }, /* SSI_SCK78 */ + { RCAR_GP_PIN(6, 18), 24, 3 }, /* SSI_WS78 */ + { RCAR_GP_PIN(6, 19), 20, 3 }, /* SSI_SDATA7 */ + { RCAR_GP_PIN(6, 20), 16, 3 }, /* SSI_SDATA8 */ + { RCAR_GP_PIN(6, 21), 12, 3 }, /* SSI_SDATA9 */ + { RCAR_GP_PIN(6, 22), 8, 3 }, /* AUDIO_CLKA */ + { RCAR_GP_PIN(6, 23), 4, 3 }, /* AUDIO_CLKB */ + { RCAR_GP_PIN(6, 24), 0, 3 }, /* USB0_PWEN */ + } }, + { PINMUX_DRIVE_REG("DRVCTRL24", 0xe6060360) { + { RCAR_GP_PIN(6, 25), 28, 3 }, /* USB0_OVC */ + { RCAR_GP_PIN(6, 26), 24, 3 }, /* USB1_PWEN */ + { RCAR_GP_PIN(6, 27), 20, 3 }, /* USB1_OVC */ + { RCAR_GP_PIN(6, 28), 16, 3 }, /* USB30_PWEN */ + { RCAR_GP_PIN(6, 29), 12, 3 }, /* USB30_OVC */ + { RCAR_GP_PIN(6, 30), 8, 3 }, /* GP6_30 */ + { RCAR_GP_PIN(6, 31), 4, 3 }, /* GP6_31 */ + } }, + { }, +}; + static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl) { int bit = -EINVAL; @@ -3221,6 +3555,7 @@ const struct sh_pfc_soc_info r8a7796_pinmux_info = { .nr_functions = ARRAY_SIZE(pinmux_functions), .cfg_regs = pinmux_config_regs, + .drive_regs = pinmux_drive_regs, .pinmux_data = pinmux_data, .pinmux_data_size = ARRAY_SIZE(pinmux_data), From 2d40bd24274d257796291804a82a0b07564a11f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Thu, 17 Nov 2016 16:09:20 +0100 Subject: [PATCH 0016/1587] pinctrl: sh-pfc: r8a7796: Add bias pinconf support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements pull-up and pull-down. On this SoC there is no simple mapping of GP pins to bias register bits, so we need a table. Signed-off-by: Niklas Söderlund Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7796.c | 354 ++++++++++++++++++++++++--- 1 file changed, 315 insertions(+), 39 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 21599ad891f0..e0fe3753963d 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -19,7 +19,9 @@ #include "core.h" #include "sh_pfc.h" -#define CFG_FLAGS SH_PFC_PIN_CFG_DRIVE_STRENGTH +#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \ + SH_PFC_PIN_CFG_PULL_UP | \ + SH_PFC_PIN_CFG_PULL_DOWN) #define CPU_ALL_PORT(fn, sfx) \ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ @@ -558,7 +560,7 @@ MOD_SEL0_2 MOD_SEL1_2 \ FM(AVB_TXCREFCLK) FM(AVB_MDIO) \ FM(PRESETOUT) \ FM(DU_DOTCLKIN0) FM(DU_DOTCLKIN1) FM(DU_DOTCLKIN2) \ - FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) + FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) FM(TDI) FM(TCK) FM(TRST) FM(EXTALR) enum { PINMUX_RESERVED = 0, @@ -1536,44 +1538,48 @@ static const struct sh_pfc_pin pinmux_pins[] = { * number for each pin. To this end use the pin layout from * R-Car M3SiP to calculate a unique number for each pin. */ - SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS), }; /* - EtherAVB --------------------------------------------------------------- */ @@ -3536,8 +3542,278 @@ static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc return bit; } +#define PUEN 0xe6060400 +#define PUD 0xe6060440 + +#define PU0 0x00 +#define PU1 0x04 +#define PU2 0x08 +#define PU3 0x0c +#define PU4 0x10 +#define PU5 0x14 +#define PU6 0x18 + +static const struct sh_pfc_bias_info bias_info[] = { + { RCAR_GP_PIN(2, 11), PU0, 31 }, /* AVB_PHY_INT */ + { RCAR_GP_PIN(2, 10), PU0, 30 }, /* AVB_MAGIC */ + { RCAR_GP_PIN(2, 9), PU0, 29 }, /* AVB_MDC */ + { PIN_NUMBER('A', 9), PU0, 28 }, /* AVB_MDIO */ + { PIN_NUMBER('A', 12), PU0, 27 }, /* AVB_TXCREFCLK */ + { PIN_NUMBER('B', 17), PU0, 26 }, /* AVB_TD3 */ + { PIN_NUMBER('A', 17), PU0, 25 }, /* AVB_TD2 */ + { PIN_NUMBER('B', 18), PU0, 24 }, /* AVB_TD1 */ + { PIN_NUMBER('A', 18), PU0, 23 }, /* AVB_TD0 */ + { PIN_NUMBER('A', 19), PU0, 22 }, /* AVB_TXC */ + { PIN_NUMBER('A', 8), PU0, 21 }, /* AVB_TX_CTL */ + { PIN_NUMBER('B', 14), PU0, 20 }, /* AVB_RD3 */ + { PIN_NUMBER('A', 14), PU0, 19 }, /* AVB_RD2 */ + { PIN_NUMBER('B', 13), PU0, 18 }, /* AVB_RD1 */ + { PIN_NUMBER('A', 13), PU0, 17 }, /* AVB_RD0 */ + { PIN_NUMBER('B', 19), PU0, 16 }, /* AVB_RXC */ + { PIN_NUMBER('A', 16), PU0, 15 }, /* AVB_RX_CTL */ + { PIN_NUMBER('V', 7), PU0, 14 }, /* RPC_RESET# */ + { PIN_NUMBER('V', 6), PU0, 13 }, /* RPC_WP# */ + { PIN_NUMBER('Y', 7), PU0, 12 }, /* RPC_INT# */ + { PIN_NUMBER('V', 5), PU0, 11 }, /* QSPI1_SSL */ + { PIN_A_NUMBER('C', 3), PU0, 10 }, /* QSPI1_IO3 */ + { PIN_A_NUMBER('E', 4), PU0, 9 }, /* QSPI1_IO2 */ + { PIN_A_NUMBER('E', 5), PU0, 8 }, /* QSPI1_MISO_IO1 */ + { PIN_A_NUMBER('C', 7), PU0, 7 }, /* QSPI1_MOSI_IO0 */ + { PIN_NUMBER('V', 3), PU0, 6 }, /* QSPI1_SPCLK */ + { PIN_NUMBER('Y', 3), PU0, 5 }, /* QSPI0_SSL */ + { PIN_A_NUMBER('B', 6), PU0, 4 }, /* QSPI0_IO3 */ + { PIN_NUMBER('Y', 6), PU0, 3 }, /* QSPI0_IO2 */ + { PIN_A_NUMBER('B', 4), PU0, 2 }, /* QSPI0_MISO_IO1 */ + { PIN_A_NUMBER('C', 5), PU0, 1 }, /* QSPI0_MOSI_IO0 */ + { PIN_NUMBER('W', 3), PU0, 0 }, /* QSPI0_SPCLK */ + + { RCAR_GP_PIN(1, 19), PU1, 31 }, /* A19 */ + { RCAR_GP_PIN(1, 18), PU1, 30 }, /* A18 */ + { RCAR_GP_PIN(1, 17), PU1, 29 }, /* A17 */ + { RCAR_GP_PIN(1, 16), PU1, 28 }, /* A16 */ + { RCAR_GP_PIN(1, 15), PU1, 27 }, /* A15 */ + { RCAR_GP_PIN(1, 14), PU1, 26 }, /* A14 */ + { RCAR_GP_PIN(1, 13), PU1, 25 }, /* A13 */ + { RCAR_GP_PIN(1, 12), PU1, 24 }, /* A12 */ + { RCAR_GP_PIN(1, 11), PU1, 23 }, /* A11 */ + { RCAR_GP_PIN(1, 10), PU1, 22 }, /* A10 */ + { RCAR_GP_PIN(1, 9), PU1, 21 }, /* A9 */ + { RCAR_GP_PIN(1, 8), PU1, 20 }, /* A8 */ + { RCAR_GP_PIN(1, 7), PU1, 19 }, /* A7 */ + { RCAR_GP_PIN(1, 6), PU1, 18 }, /* A6 */ + { RCAR_GP_PIN(1, 5), PU1, 17 }, /* A5 */ + { RCAR_GP_PIN(1, 4), PU1, 16 }, /* A4 */ + { RCAR_GP_PIN(1, 3), PU1, 15 }, /* A3 */ + { RCAR_GP_PIN(1, 2), PU1, 14 }, /* A2 */ + { RCAR_GP_PIN(1, 1), PU1, 13 }, /* A1 */ + { RCAR_GP_PIN(1, 0), PU1, 12 }, /* A0 */ + { RCAR_GP_PIN(2, 8), PU1, 11 }, /* PWM2_A */ + { RCAR_GP_PIN(2, 7), PU1, 10 }, /* PWM1_A */ + { RCAR_GP_PIN(2, 6), PU1, 9 }, /* PWM0 */ + { RCAR_GP_PIN(2, 5), PU1, 8 }, /* IRQ5 */ + { RCAR_GP_PIN(2, 4), PU1, 7 }, /* IRQ4 */ + { RCAR_GP_PIN(2, 3), PU1, 6 }, /* IRQ3 */ + { RCAR_GP_PIN(2, 2), PU1, 5 }, /* IRQ2 */ + { RCAR_GP_PIN(2, 1), PU1, 4 }, /* IRQ1 */ + { RCAR_GP_PIN(2, 0), PU1, 3 }, /* IRQ0 */ + { RCAR_GP_PIN(2, 14), PU1, 2 }, /* AVB_AVTP_CAPTURE_A */ + { RCAR_GP_PIN(2, 13), PU1, 1 }, /* AVB_AVTP_MATCH_A */ + { RCAR_GP_PIN(2, 12), PU1, 0 }, /* AVB_LINK */ + + { PIN_A_NUMBER('P', 8), PU2, 31 }, /* DU_DOTCLKIN1 */ + { PIN_A_NUMBER('P', 7), PU2, 30 }, /* DU_DOTCLKIN0 */ + { RCAR_GP_PIN(7, 3), PU2, 29 }, /* GP7_03 */ + { RCAR_GP_PIN(7, 2), PU2, 28 }, /* HDMI0_CEC */ + { RCAR_GP_PIN(7, 1), PU2, 27 }, /* AVS2 */ + { RCAR_GP_PIN(7, 0), PU2, 26 }, /* AVS1 */ + { RCAR_GP_PIN(0, 15), PU2, 25 }, /* D15 */ + { RCAR_GP_PIN(0, 14), PU2, 24 }, /* D14 */ + { RCAR_GP_PIN(0, 13), PU2, 23 }, /* D13 */ + { RCAR_GP_PIN(0, 12), PU2, 22 }, /* D12 */ + { RCAR_GP_PIN(0, 11), PU2, 21 }, /* D11 */ + { RCAR_GP_PIN(0, 10), PU2, 20 }, /* D10 */ + { RCAR_GP_PIN(0, 9), PU2, 19 }, /* D9 */ + { RCAR_GP_PIN(0, 8), PU2, 18 }, /* D8 */ + { RCAR_GP_PIN(0, 7), PU2, 17 }, /* D7 */ + { RCAR_GP_PIN(0, 6), PU2, 16 }, /* D6 */ + { RCAR_GP_PIN(0, 5), PU2, 15 }, /* D5 */ + { RCAR_GP_PIN(0, 4), PU2, 14 }, /* D4 */ + { RCAR_GP_PIN(0, 3), PU2, 13 }, /* D3 */ + { RCAR_GP_PIN(0, 2), PU2, 12 }, /* D2 */ + { RCAR_GP_PIN(0, 1), PU2, 11 }, /* D1 */ + { RCAR_GP_PIN(0, 0), PU2, 10 }, /* D0 */ + { PIN_NUMBER('C', 1), PU2, 9 }, /* PRESETOUT# */ + { RCAR_GP_PIN(1, 27), PU2, 8 }, /* EX_WAIT0_A */ + { RCAR_GP_PIN(1, 26), PU2, 7 }, /* WE1_N */ + { RCAR_GP_PIN(1, 25), PU2, 6 }, /* WE0_N */ + { RCAR_GP_PIN(1, 24), PU2, 5 }, /* RD_WR_N */ + { RCAR_GP_PIN(1, 23), PU2, 4 }, /* RD_N */ + { RCAR_GP_PIN(1, 22), PU2, 3 }, /* BS_N */ + { RCAR_GP_PIN(1, 21), PU2, 2 }, /* CS1_N_A26 */ + { RCAR_GP_PIN(1, 20), PU2, 1 }, /* CS0_N */ + { RCAR_GP_PIN(1, 28), PU2, 0 }, /* CLKOUT */ + + { RCAR_GP_PIN(4, 9), PU3, 31 }, /* SD3_DAT0 */ + { RCAR_GP_PIN(4, 8), PU3, 30 }, /* SD3_CMD */ + { RCAR_GP_PIN(4, 7), PU3, 29 }, /* SD3_CLK */ + { RCAR_GP_PIN(4, 6), PU3, 28 }, /* SD2_DS */ + { RCAR_GP_PIN(4, 5), PU3, 27 }, /* SD2_DAT3 */ + { RCAR_GP_PIN(4, 4), PU3, 26 }, /* SD2_DAT2 */ + { RCAR_GP_PIN(4, 3), PU3, 25 }, /* SD2_DAT1 */ + { RCAR_GP_PIN(4, 2), PU3, 24 }, /* SD2_DAT0 */ + { RCAR_GP_PIN(4, 1), PU3, 23 }, /* SD2_CMD */ + { RCAR_GP_PIN(4, 0), PU3, 22 }, /* SD2_CLK */ + { RCAR_GP_PIN(3, 11), PU3, 21 }, /* SD1_DAT3 */ + { RCAR_GP_PIN(3, 10), PU3, 20 }, /* SD1_DAT2 */ + { RCAR_GP_PIN(3, 9), PU3, 19 }, /* SD1_DAT1 */ + { RCAR_GP_PIN(3, 8), PU3, 18 }, /* SD1_DAT0 */ + { RCAR_GP_PIN(3, 7), PU3, 17 }, /* SD1_CMD */ + { RCAR_GP_PIN(3, 6), PU3, 16 }, /* SD1_CLK */ + { RCAR_GP_PIN(3, 5), PU3, 15 }, /* SD0_DAT3 */ + { RCAR_GP_PIN(3, 4), PU3, 14 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 3), PU3, 13 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 2), PU3, 12 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 1), PU3, 11 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 0), PU3, 10 }, /* SD0_CLK */ + { PIN_A_NUMBER('T', 30), PU3, 9 }, /* ASEBRK */ + /* bit 8 n/a */ + { PIN_A_NUMBER('R', 29), PU3, 7 }, /* TDI */ + { PIN_A_NUMBER('R', 30), PU3, 6 }, /* TMS */ + { PIN_A_NUMBER('T', 27), PU3, 5 }, /* TCK */ + { PIN_A_NUMBER('R', 26), PU3, 4 }, /* TRST# */ + { PIN_A_NUMBER('D', 39), PU3, 3 }, /* EXTALR*/ + { PIN_A_NUMBER('D', 38), PU3, 2 }, /* FSCLKST */ + /* bit 1 n/a on M3*/ + { PIN_A_NUMBER('R', 8), PU3, 0 }, /* DU_DOTCLKIN2 */ + + { RCAR_GP_PIN(5, 19), PU4, 31 }, /* MSIOF0_SS1 */ + { RCAR_GP_PIN(5, 18), PU4, 30 }, /* MSIOF0_SYNC */ + { RCAR_GP_PIN(5, 17), PU4, 29 }, /* MSIOF0_SCK */ + { RCAR_GP_PIN(5, 16), PU4, 28 }, /* HRTS0_N */ + { RCAR_GP_PIN(5, 15), PU4, 27 }, /* HCTS0_N */ + { RCAR_GP_PIN(5, 14), PU4, 26 }, /* HTX0 */ + { RCAR_GP_PIN(5, 13), PU4, 25 }, /* HRX0 */ + { RCAR_GP_PIN(5, 12), PU4, 24 }, /* HSCK0 */ + { RCAR_GP_PIN(5, 11), PU4, 23 }, /* RX2_A */ + { RCAR_GP_PIN(5, 10), PU4, 22 }, /* TX2_A */ + { RCAR_GP_PIN(5, 9), PU4, 21 }, /* SCK2 */ + { RCAR_GP_PIN(5, 8), PU4, 20 }, /* RTS1_N_TANS */ + { RCAR_GP_PIN(5, 7), PU4, 19 }, /* CTS1_N */ + { RCAR_GP_PIN(5, 6), PU4, 18 }, /* TX1_A */ + { RCAR_GP_PIN(5, 5), PU4, 17 }, /* RX1_A */ + { RCAR_GP_PIN(5, 4), PU4, 16 }, /* RTS0_N_TANS */ + { RCAR_GP_PIN(5, 3), PU4, 15 }, /* CTS0_N */ + { RCAR_GP_PIN(5, 2), PU4, 14 }, /* TX0 */ + { RCAR_GP_PIN(5, 1), PU4, 13 }, /* RX0 */ + { RCAR_GP_PIN(5, 0), PU4, 12 }, /* SCK0 */ + { RCAR_GP_PIN(3, 15), PU4, 11 }, /* SD1_WP */ + { RCAR_GP_PIN(3, 14), PU4, 10 }, /* SD1_CD */ + { RCAR_GP_PIN(3, 13), PU4, 9 }, /* SD0_WP */ + { RCAR_GP_PIN(3, 12), PU4, 8 }, /* SD0_CD */ + { RCAR_GP_PIN(4, 17), PU4, 7 }, /* SD3_DS */ + { RCAR_GP_PIN(4, 16), PU4, 6 }, /* SD3_DAT7 */ + { RCAR_GP_PIN(4, 15), PU4, 5 }, /* SD3_DAT6 */ + { RCAR_GP_PIN(4, 14), PU4, 4 }, /* SD3_DAT5 */ + { RCAR_GP_PIN(4, 13), PU4, 3 }, /* SD3_DAT4 */ + { RCAR_GP_PIN(4, 12), PU4, 2 }, /* SD3_DAT3 */ + { RCAR_GP_PIN(4, 11), PU4, 1 }, /* SD3_DAT2 */ + { RCAR_GP_PIN(4, 10), PU4, 0 }, /* SD3_DAT1 */ + + { RCAR_GP_PIN(6, 24), PU5, 31 }, /* USB0_PWEN */ + { RCAR_GP_PIN(6, 23), PU5, 30 }, /* AUDIO_CLKB_B */ + { RCAR_GP_PIN(6, 22), PU5, 29 }, /* AUDIO_CLKA_A */ + { RCAR_GP_PIN(6, 21), PU5, 28 }, /* SSI_SDATA9_A */ + { RCAR_GP_PIN(6, 20), PU5, 27 }, /* SSI_SDATA8 */ + { RCAR_GP_PIN(6, 19), PU5, 26 }, /* SSI_SDATA7 */ + { RCAR_GP_PIN(6, 18), PU5, 25 }, /* SSI_WS78 */ + { RCAR_GP_PIN(6, 17), PU5, 24 }, /* SSI_SCK78 */ + { RCAR_GP_PIN(6, 16), PU5, 23 }, /* SSI_SDATA6 */ + { RCAR_GP_PIN(6, 15), PU5, 22 }, /* SSI_WS6 */ + { RCAR_GP_PIN(6, 14), PU5, 21 }, /* SSI_SCK6 */ + { RCAR_GP_PIN(6, 13), PU5, 20 }, /* SSI_SDATA5 */ + { RCAR_GP_PIN(6, 12), PU5, 19 }, /* SSI_WS5 */ + { RCAR_GP_PIN(6, 11), PU5, 18 }, /* SSI_SCK5 */ + { RCAR_GP_PIN(6, 10), PU5, 17 }, /* SSI_SDATA4 */ + { RCAR_GP_PIN(6, 9), PU5, 16 }, /* SSI_WS4 */ + { RCAR_GP_PIN(6, 8), PU5, 15 }, /* SSI_SCK4 */ + { RCAR_GP_PIN(6, 7), PU5, 14 }, /* SSI_SDATA3 */ + { RCAR_GP_PIN(6, 6), PU5, 13 }, /* SSI_WS34 */ + { RCAR_GP_PIN(6, 5), PU5, 12 }, /* SSI_SCK34 */ + { RCAR_GP_PIN(6, 4), PU5, 11 }, /* SSI_SDATA2_A */ + { RCAR_GP_PIN(6, 3), PU5, 10 }, /* SSI_SDATA1_A */ + { RCAR_GP_PIN(6, 2), PU5, 9 }, /* SSI_SDATA0 */ + { RCAR_GP_PIN(6, 1), PU5, 8 }, /* SSI_WS01239 */ + { RCAR_GP_PIN(6, 0), PU5, 7 }, /* SSI_SCK01239 */ + { PIN_NUMBER('H', 37), PU5, 6 }, /* MLB_REF */ + { RCAR_GP_PIN(5, 25), PU5, 5 }, /* MLB_DAT */ + { RCAR_GP_PIN(5, 24), PU5, 4 }, /* MLB_SIG */ + { RCAR_GP_PIN(5, 23), PU5, 3 }, /* MLB_CLK */ + { RCAR_GP_PIN(5, 22), PU5, 2 }, /* MSIOF0_RXD */ + { RCAR_GP_PIN(5, 21), PU5, 1 }, /* MSIOF0_SS2 */ + { RCAR_GP_PIN(5, 20), PU5, 0 }, /* MSIOF0_TXD */ + + { RCAR_GP_PIN(6, 31), PU6, 6 }, /* GP6_31 */ + { RCAR_GP_PIN(6, 30), PU6, 5 }, /* GP6_30 */ + { RCAR_GP_PIN(6, 29), PU6, 4 }, /* USB30_OVC */ + { RCAR_GP_PIN(6, 28), PU6, 3 }, /* USB30_PWEN */ + { RCAR_GP_PIN(6, 27), PU6, 2 }, /* USB1_OVC */ + { RCAR_GP_PIN(6, 26), PU6, 1 }, /* USB1_PWEN */ + { RCAR_GP_PIN(6, 25), PU6, 0 }, /* USB0_OVC */ +}; + +static unsigned int r8a7796_pinmux_get_bias(struct sh_pfc *pfc, + unsigned int pin) +{ + const struct sh_pfc_bias_info *info; + u32 reg; + u32 bit; + + info = sh_pfc_pin_to_bias_info(bias_info, ARRAY_SIZE(bias_info), pin); + if (!info) + return PIN_CONFIG_BIAS_DISABLE; + + reg = info->reg; + bit = BIT(info->bit); + + if (!(sh_pfc_read_reg(pfc, PUEN + reg, 32) & bit)) + return PIN_CONFIG_BIAS_DISABLE; + else if (sh_pfc_read_reg(pfc, PUD + reg, 32) & bit) + return PIN_CONFIG_BIAS_PULL_UP; + else + return PIN_CONFIG_BIAS_PULL_DOWN; +} + +static void r8a7796_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin, + unsigned int bias) +{ + const struct sh_pfc_bias_info *info; + u32 enable, updown; + u32 reg; + u32 bit; + + info = sh_pfc_pin_to_bias_info(bias_info, ARRAY_SIZE(bias_info), pin); + if (!info) + return; + + reg = info->reg; + bit = BIT(info->bit); + + enable = sh_pfc_read_reg(pfc, PUEN + reg, 32) & ~bit; + if (bias != PIN_CONFIG_BIAS_DISABLE) + enable |= bit; + + updown = sh_pfc_read_reg(pfc, PUD + reg, 32) & ~bit; + if (bias == PIN_CONFIG_BIAS_PULL_UP) + updown |= bit; + + sh_pfc_write_reg(pfc, PUD + reg, 32, updown); + sh_pfc_write_reg(pfc, PUEN + reg, 32, enable); +} + static const struct sh_pfc_soc_operations r8a7796_pinmux_ops = { .pin_to_pocctrl = r8a7796_pin_to_pocctrl, + .get_bias = r8a7796_pinmux_get_bias, + .set_bias = r8a7796_pinmux_set_bias, }; const struct sh_pfc_soc_info r8a7796_pinmux_info = { From 4c2fb44d60b92c4e3e744f49767da23f4eaf1b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Thu, 17 Nov 2016 16:26:31 +0100 Subject: [PATCH 0017/1587] pinctrl: sh-pfc: r8a7795: Support none GPIO pins bias setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are pins on the r8a7795 which are not part of a GPIO bank nor can be muxed between different functions. They do however allow for the bias to be configured. Add those pins to the list of pins and to the bias configuration array. The pins can now be referred to in DT by function names and their bias setting set. Signed-off-by: Niklas Söderlund Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7795.c | 438 +++++++++++++++------------ 1 file changed, 243 insertions(+), 195 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index 135ed5cbeb44..504d0c3d7f74 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -538,7 +538,7 @@ MOD_SEL0_2_1 MOD_SEL1_2 \ FM(AVB_TXCREFCLK) FM(AVB_MDIO) \ FM(CLKOUT) FM(PRESETOUT) \ FM(DU_DOTCLKIN0) FM(DU_DOTCLKIN1) FM(DU_DOTCLKIN2) FM(DU_DOTCLKIN3) \ - FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) + FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) FM(TDI) FM(TCK) FM(TRST) FM(EXTALR) enum { PINMUX_RESERVED = 0, @@ -1461,46 +1461,50 @@ static const struct sh_pfc_pin pinmux_pins[] = { * number for each pin. To this end use the pin layout from * R-Car H3SiP to calculate a unique number for each pin. */ - SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('F', 1, CLKOUT, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 7, DU_DOTCLKIN2, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN3, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('F', 1, CLKOUT, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 7, DU_DOTCLKIN2, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN3, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, SH_PFC_PIN_CFG_DRIVE_STRENGTH), + SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS), }; /* - AUDIO CLOCK ------------------------------------------------------------ */ @@ -5415,167 +5419,211 @@ static int r8a7795_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc #define PU6 0x18 static const struct sh_pfc_bias_info bias_info[] = { - { RCAR_GP_PIN(2, 11), PU0, 31 }, /* AVB_PHY_INT */ - { RCAR_GP_PIN(2, 10), PU0, 30 }, /* AVB_MAGIC */ - { RCAR_GP_PIN(2, 9), PU0, 29 }, /* AVB_MDC */ + { RCAR_GP_PIN(2, 11), PU0, 31 }, /* AVB_PHY_INT */ + { RCAR_GP_PIN(2, 10), PU0, 30 }, /* AVB_MAGIC */ + { RCAR_GP_PIN(2, 9), PU0, 29 }, /* AVB_MDC */ + { PIN_NUMBER('A', 9), PU0, 28 }, /* AVB_MDIO */ + { PIN_NUMBER('A', 12), PU0, 27 }, /* AVB_TXCREFCLK */ + { PIN_NUMBER('B', 17), PU0, 26 }, /* AVB_TD3 */ + { PIN_NUMBER('A', 17), PU0, 25 }, /* AVB_TD2 */ + { PIN_NUMBER('B', 18), PU0, 24 }, /* AVB_TD1 */ + { PIN_NUMBER('A', 18), PU0, 23 }, /* AVB_TD0 */ + { PIN_NUMBER('A', 19), PU0, 22 }, /* AVB_TXC */ + { PIN_NUMBER('A', 8), PU0, 21 }, /* AVB_TX_CTL */ + { PIN_NUMBER('B', 14), PU0, 20 }, /* AVB_RD3 */ + { PIN_NUMBER('A', 14), PU0, 19 }, /* AVB_RD2 */ + { PIN_NUMBER('B', 13), PU0, 18 }, /* AVB_RD1 */ + { PIN_NUMBER('A', 13), PU0, 17 }, /* AVB_RD0 */ + { PIN_NUMBER('B', 19), PU0, 16 }, /* AVB_RXC */ + { PIN_NUMBER('A', 16), PU0, 15 }, /* AVB_RX_CTL */ + { PIN_NUMBER('V', 7), PU0, 14 }, /* RPC_RESET# */ + { PIN_NUMBER('V', 6), PU0, 13 }, /* RPC_WP# */ + { PIN_NUMBER('Y', 7), PU0, 12 }, /* RPC_INT# */ + { PIN_NUMBER('V', 5), PU0, 11 }, /* QSPI1_SSL */ + { PIN_A_NUMBER('C', 3), PU0, 10 }, /* QSPI1_IO3 */ + { PIN_A_NUMBER('E', 4), PU0, 9 }, /* QSPI1_IO2 */ + { PIN_A_NUMBER('E', 5), PU0, 8 }, /* QSPI1_MISO_IO1 */ + { PIN_A_NUMBER('C', 7), PU0, 7 }, /* QSPI1_MOSI_IO0 */ + { PIN_NUMBER('V', 3), PU0, 6 }, /* QSPI1_SPCLK */ + { PIN_NUMBER('Y', 3), PU0, 5 }, /* QSPI0_SSL */ + { PIN_A_NUMBER('B', 6), PU0, 4 }, /* QSPI0_IO3 */ + { PIN_NUMBER('Y', 6), PU0, 3 }, /* QSPI0_IO2 */ + { PIN_A_NUMBER('B', 4), PU0, 2 }, /* QSPI0_MISO_IO1 */ + { PIN_A_NUMBER('C', 5), PU0, 1 }, /* QSPI0_MOSI_IO0 */ + { PIN_NUMBER('W', 3), PU0, 0 }, /* QSPI0_SPCLK */ - { RCAR_GP_PIN(1, 19), PU1, 31 }, /* A19 */ - { RCAR_GP_PIN(1, 18), PU1, 30 }, /* A18 */ - { RCAR_GP_PIN(1, 17), PU1, 29 }, /* A17 */ - { RCAR_GP_PIN(1, 16), PU1, 28 }, /* A16 */ - { RCAR_GP_PIN(1, 15), PU1, 27 }, /* A15 */ - { RCAR_GP_PIN(1, 14), PU1, 26 }, /* A14 */ - { RCAR_GP_PIN(1, 13), PU1, 25 }, /* A13 */ - { RCAR_GP_PIN(1, 12), PU1, 24 }, /* A12 */ - { RCAR_GP_PIN(1, 11), PU1, 23 }, /* A11 */ - { RCAR_GP_PIN(1, 10), PU1, 22 }, /* A10 */ - { RCAR_GP_PIN(1, 9), PU1, 21 }, /* A9 */ - { RCAR_GP_PIN(1, 8), PU1, 20 }, /* A8 */ - { RCAR_GP_PIN(1, 7), PU1, 19 }, /* A7 */ - { RCAR_GP_PIN(1, 6), PU1, 18 }, /* A6 */ - { RCAR_GP_PIN(1, 5), PU1, 17 }, /* A5 */ - { RCAR_GP_PIN(1, 4), PU1, 16 }, /* A4 */ - { RCAR_GP_PIN(1, 3), PU1, 15 }, /* A3 */ - { RCAR_GP_PIN(1, 2), PU1, 14 }, /* A2 */ - { RCAR_GP_PIN(1, 1), PU1, 13 }, /* A1 */ - { RCAR_GP_PIN(1, 0), PU1, 12 }, /* A0 */ - { RCAR_GP_PIN(2, 8), PU1, 11 }, /* PWM2_A */ - { RCAR_GP_PIN(2, 7), PU1, 10 }, /* PWM1_A */ - { RCAR_GP_PIN(2, 6), PU1, 9 }, /* PWM0 */ - { RCAR_GP_PIN(2, 5), PU1, 8 }, /* IRQ5 */ - { RCAR_GP_PIN(2, 4), PU1, 7 }, /* IRQ4 */ - { RCAR_GP_PIN(2, 3), PU1, 6 }, /* IRQ3 */ - { RCAR_GP_PIN(2, 2), PU1, 5 }, /* IRQ2 */ - { RCAR_GP_PIN(2, 1), PU1, 4 }, /* IRQ1 */ - { RCAR_GP_PIN(2, 0), PU1, 3 }, /* IRQ0 */ - { RCAR_GP_PIN(2, 14), PU1, 2 }, /* AVB_AVTP_CAPTURE_A */ - { RCAR_GP_PIN(2, 13), PU1, 1 }, /* AVB_AVTP_MATCH_A */ - { RCAR_GP_PIN(2, 12), PU1, 0 }, /* AVB_LINK */ + { RCAR_GP_PIN(1, 19), PU1, 31 }, /* A19 */ + { RCAR_GP_PIN(1, 18), PU1, 30 }, /* A18 */ + { RCAR_GP_PIN(1, 17), PU1, 29 }, /* A17 */ + { RCAR_GP_PIN(1, 16), PU1, 28 }, /* A16 */ + { RCAR_GP_PIN(1, 15), PU1, 27 }, /* A15 */ + { RCAR_GP_PIN(1, 14), PU1, 26 }, /* A14 */ + { RCAR_GP_PIN(1, 13), PU1, 25 }, /* A13 */ + { RCAR_GP_PIN(1, 12), PU1, 24 }, /* A12 */ + { RCAR_GP_PIN(1, 11), PU1, 23 }, /* A11 */ + { RCAR_GP_PIN(1, 10), PU1, 22 }, /* A10 */ + { RCAR_GP_PIN(1, 9), PU1, 21 }, /* A9 */ + { RCAR_GP_PIN(1, 8), PU1, 20 }, /* A8 */ + { RCAR_GP_PIN(1, 7), PU1, 19 }, /* A7 */ + { RCAR_GP_PIN(1, 6), PU1, 18 }, /* A6 */ + { RCAR_GP_PIN(1, 5), PU1, 17 }, /* A5 */ + { RCAR_GP_PIN(1, 4), PU1, 16 }, /* A4 */ + { RCAR_GP_PIN(1, 3), PU1, 15 }, /* A3 */ + { RCAR_GP_PIN(1, 2), PU1, 14 }, /* A2 */ + { RCAR_GP_PIN(1, 1), PU1, 13 }, /* A1 */ + { RCAR_GP_PIN(1, 0), PU1, 12 }, /* A0 */ + { RCAR_GP_PIN(2, 8), PU1, 11 }, /* PWM2_A */ + { RCAR_GP_PIN(2, 7), PU1, 10 }, /* PWM1_A */ + { RCAR_GP_PIN(2, 6), PU1, 9 }, /* PWM0 */ + { RCAR_GP_PIN(2, 5), PU1, 8 }, /* IRQ5 */ + { RCAR_GP_PIN(2, 4), PU1, 7 }, /* IRQ4 */ + { RCAR_GP_PIN(2, 3), PU1, 6 }, /* IRQ3 */ + { RCAR_GP_PIN(2, 2), PU1, 5 }, /* IRQ2 */ + { RCAR_GP_PIN(2, 1), PU1, 4 }, /* IRQ1 */ + { RCAR_GP_PIN(2, 0), PU1, 3 }, /* IRQ0 */ + { RCAR_GP_PIN(2, 14), PU1, 2 }, /* AVB_AVTP_CAPTURE_A */ + { RCAR_GP_PIN(2, 13), PU1, 1 }, /* AVB_AVTP_MATCH_A */ + { RCAR_GP_PIN(2, 12), PU1, 0 }, /* AVB_LINK */ - { RCAR_GP_PIN(7, 3), PU2, 29 }, /* HDMI1_CEC */ - { RCAR_GP_PIN(7, 2), PU2, 28 }, /* HDMI0_CEC */ - { RCAR_GP_PIN(7, 1), PU2, 27 }, /* AVS2 */ - { RCAR_GP_PIN(7, 0), PU2, 26 }, /* AVS1 */ - { RCAR_GP_PIN(0, 15), PU2, 25 }, /* D15 */ - { RCAR_GP_PIN(0, 14), PU2, 24 }, /* D14 */ - { RCAR_GP_PIN(0, 13), PU2, 23 }, /* D13 */ - { RCAR_GP_PIN(0, 12), PU2, 22 }, /* D12 */ - { RCAR_GP_PIN(0, 11), PU2, 21 }, /* D11 */ - { RCAR_GP_PIN(0, 10), PU2, 20 }, /* D10 */ - { RCAR_GP_PIN(0, 9), PU2, 19 }, /* D9 */ - { RCAR_GP_PIN(0, 8), PU2, 18 }, /* D8 */ - { RCAR_GP_PIN(0, 7), PU2, 17 }, /* D7 */ - { RCAR_GP_PIN(0, 6), PU2, 16 }, /* D6 */ - { RCAR_GP_PIN(0, 5), PU2, 15 }, /* D5 */ - { RCAR_GP_PIN(0, 4), PU2, 14 }, /* D4 */ - { RCAR_GP_PIN(0, 3), PU2, 13 }, /* D3 */ - { RCAR_GP_PIN(0, 2), PU2, 12 }, /* D2 */ - { RCAR_GP_PIN(0, 1), PU2, 11 }, /* D1 */ - { RCAR_GP_PIN(0, 0), PU2, 10 }, /* D0 */ - { RCAR_GP_PIN(1, 27), PU2, 8 }, /* EX_WAIT0_A */ - { RCAR_GP_PIN(1, 26), PU2, 7 }, /* WE1_N */ - { RCAR_GP_PIN(1, 25), PU2, 6 }, /* WE0_N */ - { RCAR_GP_PIN(1, 24), PU2, 5 }, /* RD_WR_N */ - { RCAR_GP_PIN(1, 23), PU2, 4 }, /* RD_N */ - { RCAR_GP_PIN(1, 22), PU2, 3 }, /* BS_N */ - { RCAR_GP_PIN(1, 21), PU2, 2 }, /* CS1_N_A26 */ - { RCAR_GP_PIN(1, 20), PU2, 1 }, /* CS0_N */ + { PIN_A_NUMBER('P', 8), PU2, 31 }, /* DU_DOTCLKIN1 */ + { PIN_A_NUMBER('P', 7), PU2, 30 }, /* DU_DOTCLKIN0 */ + { RCAR_GP_PIN(7, 3), PU2, 29 }, /* HDMI1_CEC */ + { RCAR_GP_PIN(7, 2), PU2, 28 }, /* HDMI0_CEC */ + { RCAR_GP_PIN(7, 1), PU2, 27 }, /* AVS2 */ + { RCAR_GP_PIN(7, 0), PU2, 26 }, /* AVS1 */ + { RCAR_GP_PIN(0, 15), PU2, 25 }, /* D15 */ + { RCAR_GP_PIN(0, 14), PU2, 24 }, /* D14 */ + { RCAR_GP_PIN(0, 13), PU2, 23 }, /* D13 */ + { RCAR_GP_PIN(0, 12), PU2, 22 }, /* D12 */ + { RCAR_GP_PIN(0, 11), PU2, 21 }, /* D11 */ + { RCAR_GP_PIN(0, 10), PU2, 20 }, /* D10 */ + { RCAR_GP_PIN(0, 9), PU2, 19 }, /* D9 */ + { RCAR_GP_PIN(0, 8), PU2, 18 }, /* D8 */ + { RCAR_GP_PIN(0, 7), PU2, 17 }, /* D7 */ + { RCAR_GP_PIN(0, 6), PU2, 16 }, /* D6 */ + { RCAR_GP_PIN(0, 5), PU2, 15 }, /* D5 */ + { RCAR_GP_PIN(0, 4), PU2, 14 }, /* D4 */ + { RCAR_GP_PIN(0, 3), PU2, 13 }, /* D3 */ + { RCAR_GP_PIN(0, 2), PU2, 12 }, /* D2 */ + { RCAR_GP_PIN(0, 1), PU2, 11 }, /* D1 */ + { RCAR_GP_PIN(0, 0), PU2, 10 }, /* D0 */ + { PIN_NUMBER('C', 1), PU2, 9 }, /* PRESETOUT# */ + { RCAR_GP_PIN(1, 27), PU2, 8 }, /* EX_WAIT0_A */ + { RCAR_GP_PIN(1, 26), PU2, 7 }, /* WE1_N */ + { RCAR_GP_PIN(1, 25), PU2, 6 }, /* WE0_N */ + { RCAR_GP_PIN(1, 24), PU2, 5 }, /* RD_WR_N */ + { RCAR_GP_PIN(1, 23), PU2, 4 }, /* RD_N */ + { RCAR_GP_PIN(1, 22), PU2, 3 }, /* BS_N */ + { RCAR_GP_PIN(1, 21), PU2, 2 }, /* CS1_N_A26 */ + { RCAR_GP_PIN(1, 20), PU2, 1 }, /* CS0_N */ + { PIN_NUMBER('F', 1), PU2, 0 }, /* CLKOUT */ - { RCAR_GP_PIN(4, 9), PU3, 31 }, /* SD3_DAT0 */ - { RCAR_GP_PIN(4, 8), PU3, 30 }, /* SD3_CMD */ - { RCAR_GP_PIN(4, 7), PU3, 29 }, /* SD3_CLK */ - { RCAR_GP_PIN(4, 6), PU3, 28 }, /* SD2_DS */ - { RCAR_GP_PIN(4, 5), PU3, 27 }, /* SD2_DAT3 */ - { RCAR_GP_PIN(4, 4), PU3, 26 }, /* SD2_DAT2 */ - { RCAR_GP_PIN(4, 3), PU3, 25 }, /* SD2_DAT1 */ - { RCAR_GP_PIN(4, 2), PU3, 24 }, /* SD2_DAT0 */ - { RCAR_GP_PIN(4, 1), PU3, 23 }, /* SD2_CMD */ - { RCAR_GP_PIN(4, 0), PU3, 22 }, /* SD2_CLK */ - { RCAR_GP_PIN(3, 11), PU3, 21 }, /* SD1_DAT3 */ - { RCAR_GP_PIN(3, 10), PU3, 20 }, /* SD1_DAT2 */ - { RCAR_GP_PIN(3, 9), PU3, 19 }, /* SD1_DAT1 */ - { RCAR_GP_PIN(3, 8), PU3, 18 }, /* SD1_DAT0 */ - { RCAR_GP_PIN(3, 7), PU3, 17 }, /* SD1_CMD */ - { RCAR_GP_PIN(3, 6), PU3, 16 }, /* SD1_CLK */ - { RCAR_GP_PIN(3, 5), PU3, 15 }, /* SD0_DAT3 */ - { RCAR_GP_PIN(3, 4), PU3, 14 }, /* SD0_DAT2 */ - { RCAR_GP_PIN(3, 3), PU3, 13 }, /* SD0_DAT1 */ - { RCAR_GP_PIN(3, 2), PU3, 12 }, /* SD0_DAT0 */ - { RCAR_GP_PIN(3, 1), PU3, 11 }, /* SD0_CMD */ - { RCAR_GP_PIN(3, 0), PU3, 10 }, /* SD0_CLK */ + { RCAR_GP_PIN(4, 9), PU3, 31 }, /* SD3_DAT0 */ + { RCAR_GP_PIN(4, 8), PU3, 30 }, /* SD3_CMD */ + { RCAR_GP_PIN(4, 7), PU3, 29 }, /* SD3_CLK */ + { RCAR_GP_PIN(4, 6), PU3, 28 }, /* SD2_DS */ + { RCAR_GP_PIN(4, 5), PU3, 27 }, /* SD2_DAT3 */ + { RCAR_GP_PIN(4, 4), PU3, 26 }, /* SD2_DAT2 */ + { RCAR_GP_PIN(4, 3), PU3, 25 }, /* SD2_DAT1 */ + { RCAR_GP_PIN(4, 2), PU3, 24 }, /* SD2_DAT0 */ + { RCAR_GP_PIN(4, 1), PU3, 23 }, /* SD2_CMD */ + { RCAR_GP_PIN(4, 0), PU3, 22 }, /* SD2_CLK */ + { RCAR_GP_PIN(3, 11), PU3, 21 }, /* SD1_DAT3 */ + { RCAR_GP_PIN(3, 10), PU3, 20 }, /* SD1_DAT2 */ + { RCAR_GP_PIN(3, 9), PU3, 19 }, /* SD1_DAT1 */ + { RCAR_GP_PIN(3, 8), PU3, 18 }, /* SD1_DAT0 */ + { RCAR_GP_PIN(3, 7), PU3, 17 }, /* SD1_CMD */ + { RCAR_GP_PIN(3, 6), PU3, 16 }, /* SD1_CLK */ + { RCAR_GP_PIN(3, 5), PU3, 15 }, /* SD0_DAT3 */ + { RCAR_GP_PIN(3, 4), PU3, 14 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 3), PU3, 13 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 2), PU3, 12 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 1), PU3, 11 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 0), PU3, 10 }, /* SD0_CLK */ + { PIN_A_NUMBER('T', 30), PU3, 9 }, /* ASEBRK */ + /* bit 8 n/a */ + { PIN_A_NUMBER('R', 29), PU3, 7 }, /* TDI */ + { PIN_A_NUMBER('R', 30), PU3, 6 }, /* TMS */ + { PIN_A_NUMBER('T', 27), PU3, 5 }, /* TCK */ + { PIN_A_NUMBER('R', 26), PU3, 4 }, /* TRST# */ + { PIN_A_NUMBER('D', 39), PU3, 3 }, /* EXTALR*/ + { PIN_A_NUMBER('D', 38), PU3, 2 }, /* FSCLKST# */ + { PIN_A_NUMBER('R', 8), PU3, 1 }, /* DU_DOTCLKIN3 */ + { PIN_A_NUMBER('R', 7), PU3, 0 }, /* DU_DOTCLKIN2 */ - { RCAR_GP_PIN(5, 19), PU4, 31 }, /* MSIOF0_SS1 */ - { RCAR_GP_PIN(5, 18), PU4, 30 }, /* MSIOF0_SYNC */ - { RCAR_GP_PIN(5, 17), PU4, 29 }, /* MSIOF0_SCK */ - { RCAR_GP_PIN(5, 16), PU4, 28 }, /* HRTS0_N */ - { RCAR_GP_PIN(5, 15), PU4, 27 }, /* HCTS0_N */ - { RCAR_GP_PIN(5, 14), PU4, 26 }, /* HTX0 */ - { RCAR_GP_PIN(5, 13), PU4, 25 }, /* HRX0 */ - { RCAR_GP_PIN(5, 12), PU4, 24 }, /* HSCK0 */ - { RCAR_GP_PIN(5, 11), PU4, 23 }, /* RX2_A */ - { RCAR_GP_PIN(5, 10), PU4, 22 }, /* TX2_A */ - { RCAR_GP_PIN(5, 9), PU4, 21 }, /* SCK2 */ - { RCAR_GP_PIN(5, 8), PU4, 20 }, /* RTS1_N_TANS */ - { RCAR_GP_PIN(5, 7), PU4, 19 }, /* CTS1_N */ - { RCAR_GP_PIN(5, 6), PU4, 18 }, /* TX1_A */ - { RCAR_GP_PIN(5, 5), PU4, 17 }, /* RX1_A */ - { RCAR_GP_PIN(5, 4), PU4, 16 }, /* RTS0_N_TANS */ - { RCAR_GP_PIN(5, 3), PU4, 15 }, /* CTS0_N */ - { RCAR_GP_PIN(5, 2), PU4, 14 }, /* TX0 */ - { RCAR_GP_PIN(5, 1), PU4, 13 }, /* RX0 */ - { RCAR_GP_PIN(5, 0), PU4, 12 }, /* SCK0 */ - { RCAR_GP_PIN(3, 15), PU4, 11 }, /* SD1_WP */ - { RCAR_GP_PIN(3, 14), PU4, 10 }, /* SD1_CD */ - { RCAR_GP_PIN(3, 13), PU4, 9 }, /* SD0_WP */ - { RCAR_GP_PIN(3, 12), PU4, 8 }, /* SD0_CD */ - { RCAR_GP_PIN(4, 17), PU4, 7 }, /* SD3_DS */ - { RCAR_GP_PIN(4, 16), PU4, 6 }, /* SD3_DAT7 */ - { RCAR_GP_PIN(4, 15), PU4, 5 }, /* SD3_DAT6 */ - { RCAR_GP_PIN(4, 14), PU4, 4 }, /* SD3_DAT5 */ - { RCAR_GP_PIN(4, 13), PU4, 3 }, /* SD3_DAT4 */ - { RCAR_GP_PIN(4, 12), PU4, 2 }, /* SD3_DAT3 */ - { RCAR_GP_PIN(4, 11), PU4, 1 }, /* SD3_DAT2 */ - { RCAR_GP_PIN(4, 10), PU4, 0 }, /* SD3_DAT1 */ + { RCAR_GP_PIN(5, 19), PU4, 31 }, /* MSIOF0_SS1 */ + { RCAR_GP_PIN(5, 18), PU4, 30 }, /* MSIOF0_SYNC */ + { RCAR_GP_PIN(5, 17), PU4, 29 }, /* MSIOF0_SCK */ + { RCAR_GP_PIN(5, 16), PU4, 28 }, /* HRTS0_N */ + { RCAR_GP_PIN(5, 15), PU4, 27 }, /* HCTS0_N */ + { RCAR_GP_PIN(5, 14), PU4, 26 }, /* HTX0 */ + { RCAR_GP_PIN(5, 13), PU4, 25 }, /* HRX0 */ + { RCAR_GP_PIN(5, 12), PU4, 24 }, /* HSCK0 */ + { RCAR_GP_PIN(5, 11), PU4, 23 }, /* RX2_A */ + { RCAR_GP_PIN(5, 10), PU4, 22 }, /* TX2_A */ + { RCAR_GP_PIN(5, 9), PU4, 21 }, /* SCK2 */ + { RCAR_GP_PIN(5, 8), PU4, 20 }, /* RTS1_N_TANS */ + { RCAR_GP_PIN(5, 7), PU4, 19 }, /* CTS1_N */ + { RCAR_GP_PIN(5, 6), PU4, 18 }, /* TX1_A */ + { RCAR_GP_PIN(5, 5), PU4, 17 }, /* RX1_A */ + { RCAR_GP_PIN(5, 4), PU4, 16 }, /* RTS0_N_TANS */ + { RCAR_GP_PIN(5, 3), PU4, 15 }, /* CTS0_N */ + { RCAR_GP_PIN(5, 2), PU4, 14 }, /* TX0 */ + { RCAR_GP_PIN(5, 1), PU4, 13 }, /* RX0 */ + { RCAR_GP_PIN(5, 0), PU4, 12 }, /* SCK0 */ + { RCAR_GP_PIN(3, 15), PU4, 11 }, /* SD1_WP */ + { RCAR_GP_PIN(3, 14), PU4, 10 }, /* SD1_CD */ + { RCAR_GP_PIN(3, 13), PU4, 9 }, /* SD0_WP */ + { RCAR_GP_PIN(3, 12), PU4, 8 }, /* SD0_CD */ + { RCAR_GP_PIN(4, 17), PU4, 7 }, /* SD3_DS */ + { RCAR_GP_PIN(4, 16), PU4, 6 }, /* SD3_DAT7 */ + { RCAR_GP_PIN(4, 15), PU4, 5 }, /* SD3_DAT6 */ + { RCAR_GP_PIN(4, 14), PU4, 4 }, /* SD3_DAT5 */ + { RCAR_GP_PIN(4, 13), PU4, 3 }, /* SD3_DAT4 */ + { RCAR_GP_PIN(4, 12), PU4, 2 }, /* SD3_DAT3 */ + { RCAR_GP_PIN(4, 11), PU4, 1 }, /* SD3_DAT2 */ + { RCAR_GP_PIN(4, 10), PU4, 0 }, /* SD3_DAT1 */ - { RCAR_GP_PIN(6, 24), PU5, 31 }, /* USB0_PWEN */ - { RCAR_GP_PIN(6, 23), PU5, 30 }, /* AUDIO_CLKB_B */ - { RCAR_GP_PIN(6, 22), PU5, 29 }, /* AUDIO_CLKA_A */ - { RCAR_GP_PIN(6, 21), PU5, 28 }, /* SSI_SDATA9_A */ - { RCAR_GP_PIN(6, 20), PU5, 27 }, /* SSI_SDATA8 */ - { RCAR_GP_PIN(6, 19), PU5, 26 }, /* SSI_SDATA7 */ - { RCAR_GP_PIN(6, 18), PU5, 25 }, /* SSI_WS78 */ - { RCAR_GP_PIN(6, 17), PU5, 24 }, /* SSI_SCK78 */ - { RCAR_GP_PIN(6, 16), PU5, 23 }, /* SSI_SDATA6 */ - { RCAR_GP_PIN(6, 15), PU5, 22 }, /* SSI_WS6 */ - { RCAR_GP_PIN(6, 14), PU5, 21 }, /* SSI_SCK6 */ - { RCAR_GP_PIN(6, 13), PU5, 20 }, /* SSI_SDATA5 */ - { RCAR_GP_PIN(6, 12), PU5, 19 }, /* SSI_WS5 */ - { RCAR_GP_PIN(6, 11), PU5, 18 }, /* SSI_SCK5 */ - { RCAR_GP_PIN(6, 10), PU5, 17 }, /* SSI_SDATA4 */ - { RCAR_GP_PIN(6, 9), PU5, 16 }, /* SSI_WS4 */ - { RCAR_GP_PIN(6, 8), PU5, 15 }, /* SSI_SCK4 */ - { RCAR_GP_PIN(6, 7), PU5, 14 }, /* SSI_SDATA3 */ - { RCAR_GP_PIN(6, 6), PU5, 13 }, /* SSI_WS34 */ - { RCAR_GP_PIN(6, 5), PU5, 12 }, /* SSI_SCK34 */ - { RCAR_GP_PIN(6, 4), PU5, 11 }, /* SSI_SDATA2_A */ - { RCAR_GP_PIN(6, 3), PU5, 10 }, /* SSI_SDATA1_A */ - { RCAR_GP_PIN(6, 2), PU5, 9 }, /* SSI_SDATA0 */ - { RCAR_GP_PIN(6, 1), PU5, 8 }, /* SSI_WS01239 */ - { RCAR_GP_PIN(6, 0), PU5, 7 }, /* SSI_SCK01239 */ - { RCAR_GP_PIN(5, 25), PU5, 5 }, /* MLB_DAT */ - { RCAR_GP_PIN(5, 24), PU5, 4 }, /* MLB_SIG */ - { RCAR_GP_PIN(5, 23), PU5, 3 }, /* MLB_CLK */ - { RCAR_GP_PIN(5, 22), PU5, 2 }, /* MSIOF0_RXD */ - { RCAR_GP_PIN(5, 21), PU5, 1 }, /* MSIOF0_SS2 */ - { RCAR_GP_PIN(5, 20), PU5, 0 }, /* MSIOF0_TXD */ + { RCAR_GP_PIN(6, 24), PU5, 31 }, /* USB0_PWEN */ + { RCAR_GP_PIN(6, 23), PU5, 30 }, /* AUDIO_CLKB_B */ + { RCAR_GP_PIN(6, 22), PU5, 29 }, /* AUDIO_CLKA_A */ + { RCAR_GP_PIN(6, 21), PU5, 28 }, /* SSI_SDATA9_A */ + { RCAR_GP_PIN(6, 20), PU5, 27 }, /* SSI_SDATA8 */ + { RCAR_GP_PIN(6, 19), PU5, 26 }, /* SSI_SDATA7 */ + { RCAR_GP_PIN(6, 18), PU5, 25 }, /* SSI_WS78 */ + { RCAR_GP_PIN(6, 17), PU5, 24 }, /* SSI_SCK78 */ + { RCAR_GP_PIN(6, 16), PU5, 23 }, /* SSI_SDATA6 */ + { RCAR_GP_PIN(6, 15), PU5, 22 }, /* SSI_WS6 */ + { RCAR_GP_PIN(6, 14), PU5, 21 }, /* SSI_SCK6 */ + { RCAR_GP_PIN(6, 13), PU5, 20 }, /* SSI_SDATA5 */ + { RCAR_GP_PIN(6, 12), PU5, 19 }, /* SSI_WS5 */ + { RCAR_GP_PIN(6, 11), PU5, 18 }, /* SSI_SCK5 */ + { RCAR_GP_PIN(6, 10), PU5, 17 }, /* SSI_SDATA4 */ + { RCAR_GP_PIN(6, 9), PU5, 16 }, /* SSI_WS4 */ + { RCAR_GP_PIN(6, 8), PU5, 15 }, /* SSI_SCK4 */ + { RCAR_GP_PIN(6, 7), PU5, 14 }, /* SSI_SDATA3 */ + { RCAR_GP_PIN(6, 6), PU5, 13 }, /* SSI_WS34 */ + { RCAR_GP_PIN(6, 5), PU5, 12 }, /* SSI_SCK34 */ + { RCAR_GP_PIN(6, 4), PU5, 11 }, /* SSI_SDATA2_A */ + { RCAR_GP_PIN(6, 3), PU5, 10 }, /* SSI_SDATA1_A */ + { RCAR_GP_PIN(6, 2), PU5, 9 }, /* SSI_SDATA0 */ + { RCAR_GP_PIN(6, 1), PU5, 8 }, /* SSI_WS01239 */ + { RCAR_GP_PIN(6, 0), PU5, 7 }, /* SSI_SCK01239 */ + { PIN_NUMBER('H', 37), PU5, 6 }, /* MLB_REF */ + { RCAR_GP_PIN(5, 25), PU5, 5 }, /* MLB_DAT */ + { RCAR_GP_PIN(5, 24), PU5, 4 }, /* MLB_SIG */ + { RCAR_GP_PIN(5, 23), PU5, 3 }, /* MLB_CLK */ + { RCAR_GP_PIN(5, 22), PU5, 2 }, /* MSIOF0_RXD */ + { RCAR_GP_PIN(5, 21), PU5, 1 }, /* MSIOF0_SS2 */ + { RCAR_GP_PIN(5, 20), PU5, 0 }, /* MSIOF0_TXD */ - { RCAR_GP_PIN(6, 31), PU6, 6 }, /* USB31_OVC */ - { RCAR_GP_PIN(6, 30), PU6, 5 }, /* USB31_PWEN */ - { RCAR_GP_PIN(6, 29), PU6, 4 }, /* USB30_OVC */ - { RCAR_GP_PIN(6, 28), PU6, 3 }, /* USB30_PWEN */ - { RCAR_GP_PIN(6, 27), PU6, 2 }, /* USB1_OVC */ - { RCAR_GP_PIN(6, 26), PU6, 1 }, /* USB1_PWEN */ - { RCAR_GP_PIN(6, 25), PU6, 0 }, /* USB0_OVC */ + { RCAR_GP_PIN(6, 31), PU6, 6 }, /* USB31_OVC */ + { RCAR_GP_PIN(6, 30), PU6, 5 }, /* USB31_PWEN */ + { RCAR_GP_PIN(6, 29), PU6, 4 }, /* USB30_OVC */ + { RCAR_GP_PIN(6, 28), PU6, 3 }, /* USB30_PWEN */ + { RCAR_GP_PIN(6, 27), PU6, 2 }, /* USB1_OVC */ + { RCAR_GP_PIN(6, 26), PU6, 1 }, /* USB1_PWEN */ + { RCAR_GP_PIN(6, 25), PU6, 0 }, /* USB0_OVC */ }; static unsigned int r8a7795_pinmux_get_bias(struct sh_pfc *pfc, From cf75341accab1a90895936cff380c38f6d0777f5 Mon Sep 17 00:00:00 2001 From: Chris Paterson Date: Tue, 22 Nov 2016 13:49:02 +0000 Subject: [PATCH 0018/1587] pinctrl: sh-pfc: r8a7796: Add CAN support This patch adds CAN[0-1] pinmux support to r8a7796 SoC. Based on a patch for r8a7795 by Ramesh Shanmugasundaram. Signed-off-by: Chris Paterson Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7796.c | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index e0fe3753963d..cd7157a8543f 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -1647,6 +1647,38 @@ static const unsigned int avb_avtp_capture_b_mux[] = { AVB_AVTP_CAPTURE_B_MARK, }; +/* - CAN ------------------------------------------------------------------ */ +static const unsigned int can0_data_a_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), +}; +static const unsigned int can0_data_a_mux[] = { + CAN0_TX_A_MARK, CAN0_RX_A_MARK, +}; +static const unsigned int can0_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), +}; +static const unsigned int can0_data_b_mux[] = { + CAN0_TX_B_MARK, CAN0_RX_B_MARK, +}; +static const unsigned int can1_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 26), +}; +static const unsigned int can1_data_mux[] = { + CAN1_TX_MARK, CAN1_RX_MARK, +}; + +/* - CAN Clock -------------------------------------------------------------- */ +static const unsigned int can_clk_pins[] = { + /* CLK */ + RCAR_GP_PIN(1, 25), +}; +static const unsigned int can_clk_mux[] = { + CAN_CLK_MARK, +}; + /* - DRIF0 --------------------------------------------------------------- */ static const unsigned int drif0_ctrl_a_pins[] = { /* CLK, SYNC */ @@ -2425,6 +2457,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(avb_avtp_capture_a), SH_PFC_PIN_GROUP(avb_avtp_match_b), SH_PFC_PIN_GROUP(avb_avtp_capture_b), + SH_PFC_PIN_GROUP(can0_data_a), + SH_PFC_PIN_GROUP(can0_data_b), + SH_PFC_PIN_GROUP(can1_data), + SH_PFC_PIN_GROUP(can_clk), SH_PFC_PIN_GROUP(drif0_ctrl_a), SH_PFC_PIN_GROUP(drif0_data0_a), SH_PFC_PIN_GROUP(drif0_data1_a), @@ -2539,6 +2575,19 @@ static const char * const avb_groups[] = { "avb_avtp_capture_b", }; +static const char * const can0_groups[] = { + "can0_data_a", + "can0_data_b", +}; + +static const char * const can1_groups[] = { + "can1_data", +}; + +static const char * const can_clk_groups[] = { + "can_clk", +}; + static const char * const drif0_groups[] = { "drif0_ctrl_a", "drif0_data0_a", @@ -2698,6 +2747,9 @@ static const char * const sdhi3_groups[] = { static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(avb), + SH_PFC_FUNCTION(can0), + SH_PFC_FUNCTION(can1), + SH_PFC_FUNCTION(can_clk), SH_PFC_FUNCTION(drif0), SH_PFC_FUNCTION(drif1), SH_PFC_FUNCTION(drif2), From 3dc93dcea67c967308db8ba00bac1334cf43a083 Mon Sep 17 00:00:00 2001 From: Chris Paterson Date: Tue, 22 Nov 2016 13:49:03 +0000 Subject: [PATCH 0019/1587] pinctrl: sh-pfc: r8a7796: Add CAN FD support This patch adds CAN FD[0-1] pinmux support to r8a7796 SoC. Based on a patch for r8a7795 by Ramesh Shanmugasundaram. Signed-off-by: Chris Paterson Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7796.c | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index cd7157a8543f..30cbc0d20b08 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -1679,6 +1679,29 @@ static const unsigned int can_clk_mux[] = { CAN_CLK_MARK, }; +/* - CAN FD --------------------------------------------------------------- */ +static const unsigned int canfd0_data_a_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), +}; +static const unsigned int canfd0_data_a_mux[] = { + CANFD0_TX_A_MARK, CANFD0_RX_A_MARK, +}; +static const unsigned int canfd0_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), +}; +static const unsigned int canfd0_data_b_mux[] = { + CANFD0_TX_B_MARK, CANFD0_RX_B_MARK, +}; +static const unsigned int canfd1_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 26), +}; +static const unsigned int canfd1_data_mux[] = { + CANFD1_TX_MARK, CANFD1_RX_MARK, +}; + /* - DRIF0 --------------------------------------------------------------- */ static const unsigned int drif0_ctrl_a_pins[] = { /* CLK, SYNC */ @@ -2461,6 +2484,9 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(can0_data_b), SH_PFC_PIN_GROUP(can1_data), SH_PFC_PIN_GROUP(can_clk), + SH_PFC_PIN_GROUP(canfd0_data_a), + SH_PFC_PIN_GROUP(canfd0_data_b), + SH_PFC_PIN_GROUP(canfd1_data), SH_PFC_PIN_GROUP(drif0_ctrl_a), SH_PFC_PIN_GROUP(drif0_data0_a), SH_PFC_PIN_GROUP(drif0_data1_a), @@ -2588,6 +2614,15 @@ static const char * const can_clk_groups[] = { "can_clk", }; +static const char * const canfd0_groups[] = { + "canfd0_data_a", + "canfd0_data_b", +}; + +static const char * const canfd1_groups[] = { + "canfd1_data", +}; + static const char * const drif0_groups[] = { "drif0_ctrl_a", "drif0_data0_a", @@ -2750,6 +2785,8 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(can0), SH_PFC_FUNCTION(can1), SH_PFC_FUNCTION(can_clk), + SH_PFC_FUNCTION(canfd0), + SH_PFC_FUNCTION(canfd1), SH_PFC_FUNCTION(drif0), SH_PFC_FUNCTION(drif1), SH_PFC_FUNCTION(drif2), From 4753231cc94683903135b9ca6d71eaab79f81349 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Wed, 16 Mar 2016 12:22:06 +0900 Subject: [PATCH 0020/1587] pinctrl: sh-pfc: r8a7796: Add MSIOF pins, groups and functions This patch adds MSIOF{0,1,2,3} pins, groups and functions to R8A7796 SoC. Signed-off-by: Takeshi Kihara [geert: Correct MSIOF3 SS1_E/SS2_E pins] Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7796.c | 913 +++++++++++++++++++++++++++ 1 file changed, 913 insertions(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 30cbc0d20b08..34a05d774172 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -2049,6 +2049,705 @@ static const unsigned int i2c6_c_mux[] = { SDA6_C_MARK, SCL6_C_MARK, }; +/* - MSIOF0 ----------------------------------------------------------------- */ +static const unsigned int msiof0_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 17), +}; +static const unsigned int msiof0_clk_mux[] = { + MSIOF0_SCK_MARK, +}; +static const unsigned int msiof0_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(5, 18), +}; +static const unsigned int msiof0_sync_mux[] = { + MSIOF0_SYNC_MARK, +}; +static const unsigned int msiof0_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(5, 19), +}; +static const unsigned int msiof0_ss1_mux[] = { + MSIOF0_SS1_MARK, +}; +static const unsigned int msiof0_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(5, 21), +}; +static const unsigned int msiof0_ss2_mux[] = { + MSIOF0_SS2_MARK, +}; +static const unsigned int msiof0_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(5, 20), +}; +static const unsigned int msiof0_txd_mux[] = { + MSIOF0_TXD_MARK, +}; +static const unsigned int msiof0_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(5, 22), +}; +static const unsigned int msiof0_rxd_mux[] = { + MSIOF0_RXD_MARK, +}; +/* - MSIOF1 ----------------------------------------------------------------- */ +static const unsigned int msiof1_clk_a_pins[] = { + /* SCK */ + RCAR_GP_PIN(6, 8), +}; +static const unsigned int msiof1_clk_a_mux[] = { + MSIOF1_SCK_A_MARK, +}; +static const unsigned int msiof1_sync_a_pins[] = { + /* SYNC */ + RCAR_GP_PIN(6, 9), +}; +static const unsigned int msiof1_sync_a_mux[] = { + MSIOF1_SYNC_A_MARK, +}; +static const unsigned int msiof1_ss1_a_pins[] = { + /* SS1 */ + RCAR_GP_PIN(6, 5), +}; +static const unsigned int msiof1_ss1_a_mux[] = { + MSIOF1_SS1_A_MARK, +}; +static const unsigned int msiof1_ss2_a_pins[] = { + /* SS2 */ + RCAR_GP_PIN(6, 6), +}; +static const unsigned int msiof1_ss2_a_mux[] = { + MSIOF1_SS2_A_MARK, +}; +static const unsigned int msiof1_txd_a_pins[] = { + /* TXD */ + RCAR_GP_PIN(6, 7), +}; +static const unsigned int msiof1_txd_a_mux[] = { + MSIOF1_TXD_A_MARK, +}; +static const unsigned int msiof1_rxd_a_pins[] = { + /* RXD */ + RCAR_GP_PIN(6, 10), +}; +static const unsigned int msiof1_rxd_a_mux[] = { + MSIOF1_RXD_A_MARK, +}; +static const unsigned int msiof1_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 9), +}; +static const unsigned int msiof1_clk_b_mux[] = { + MSIOF1_SCK_B_MARK, +}; +static const unsigned int msiof1_sync_b_pins[] = { + /* SYNC */ + RCAR_GP_PIN(5, 3), +}; +static const unsigned int msiof1_sync_b_mux[] = { + MSIOF1_SYNC_B_MARK, +}; +static const unsigned int msiof1_ss1_b_pins[] = { + /* SS1 */ + RCAR_GP_PIN(5, 4), +}; +static const unsigned int msiof1_ss1_b_mux[] = { + MSIOF1_SS1_B_MARK, +}; +static const unsigned int msiof1_ss2_b_pins[] = { + /* SS2 */ + RCAR_GP_PIN(5, 0), +}; +static const unsigned int msiof1_ss2_b_mux[] = { + MSIOF1_SS2_B_MARK, +}; +static const unsigned int msiof1_txd_b_pins[] = { + /* TXD */ + RCAR_GP_PIN(5, 8), +}; +static const unsigned int msiof1_txd_b_mux[] = { + MSIOF1_TXD_B_MARK, +}; +static const unsigned int msiof1_rxd_b_pins[] = { + /* RXD */ + RCAR_GP_PIN(5, 7), +}; +static const unsigned int msiof1_rxd_b_mux[] = { + MSIOF1_RXD_B_MARK, +}; +static const unsigned int msiof1_clk_c_pins[] = { + /* SCK */ + RCAR_GP_PIN(6, 17), +}; +static const unsigned int msiof1_clk_c_mux[] = { + MSIOF1_SCK_C_MARK, +}; +static const unsigned int msiof1_sync_c_pins[] = { + /* SYNC */ + RCAR_GP_PIN(6, 18), +}; +static const unsigned int msiof1_sync_c_mux[] = { + MSIOF1_SYNC_C_MARK, +}; +static const unsigned int msiof1_ss1_c_pins[] = { + /* SS1 */ + RCAR_GP_PIN(6, 21), +}; +static const unsigned int msiof1_ss1_c_mux[] = { + MSIOF1_SS1_C_MARK, +}; +static const unsigned int msiof1_ss2_c_pins[] = { + /* SS2 */ + RCAR_GP_PIN(6, 27), +}; +static const unsigned int msiof1_ss2_c_mux[] = { + MSIOF1_SS2_C_MARK, +}; +static const unsigned int msiof1_txd_c_pins[] = { + /* TXD */ + RCAR_GP_PIN(6, 20), +}; +static const unsigned int msiof1_txd_c_mux[] = { + MSIOF1_TXD_C_MARK, +}; +static const unsigned int msiof1_rxd_c_pins[] = { + /* RXD */ + RCAR_GP_PIN(6, 19), +}; +static const unsigned int msiof1_rxd_c_mux[] = { + MSIOF1_RXD_C_MARK, +}; +static const unsigned int msiof1_clk_d_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 12), +}; +static const unsigned int msiof1_clk_d_mux[] = { + MSIOF1_SCK_D_MARK, +}; +static const unsigned int msiof1_sync_d_pins[] = { + /* SYNC */ + RCAR_GP_PIN(5, 15), +}; +static const unsigned int msiof1_sync_d_mux[] = { + MSIOF1_SYNC_D_MARK, +}; +static const unsigned int msiof1_ss1_d_pins[] = { + /* SS1 */ + RCAR_GP_PIN(5, 16), +}; +static const unsigned int msiof1_ss1_d_mux[] = { + MSIOF1_SS1_D_MARK, +}; +static const unsigned int msiof1_ss2_d_pins[] = { + /* SS2 */ + RCAR_GP_PIN(5, 21), +}; +static const unsigned int msiof1_ss2_d_mux[] = { + MSIOF1_SS2_D_MARK, +}; +static const unsigned int msiof1_txd_d_pins[] = { + /* TXD */ + RCAR_GP_PIN(5, 14), +}; +static const unsigned int msiof1_txd_d_mux[] = { + MSIOF1_TXD_D_MARK, +}; +static const unsigned int msiof1_rxd_d_pins[] = { + /* RXD */ + RCAR_GP_PIN(5, 13), +}; +static const unsigned int msiof1_rxd_d_mux[] = { + MSIOF1_RXD_D_MARK, +}; +static const unsigned int msiof1_clk_e_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 0), +}; +static const unsigned int msiof1_clk_e_mux[] = { + MSIOF1_SCK_E_MARK, +}; +static const unsigned int msiof1_sync_e_pins[] = { + /* SYNC */ + RCAR_GP_PIN(3, 1), +}; +static const unsigned int msiof1_sync_e_mux[] = { + MSIOF1_SYNC_E_MARK, +}; +static const unsigned int msiof1_ss1_e_pins[] = { + /* SS1 */ + RCAR_GP_PIN(3, 4), +}; +static const unsigned int msiof1_ss1_e_mux[] = { + MSIOF1_SS1_E_MARK, +}; +static const unsigned int msiof1_ss2_e_pins[] = { + /* SS2 */ + RCAR_GP_PIN(3, 5), +}; +static const unsigned int msiof1_ss2_e_mux[] = { + MSIOF1_SS2_E_MARK, +}; +static const unsigned int msiof1_txd_e_pins[] = { + /* TXD */ + RCAR_GP_PIN(3, 3), +}; +static const unsigned int msiof1_txd_e_mux[] = { + MSIOF1_TXD_E_MARK, +}; +static const unsigned int msiof1_rxd_e_pins[] = { + /* RXD */ + RCAR_GP_PIN(3, 2), +}; +static const unsigned int msiof1_rxd_e_mux[] = { + MSIOF1_RXD_E_MARK, +}; +static const unsigned int msiof1_clk_f_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 23), +}; +static const unsigned int msiof1_clk_f_mux[] = { + MSIOF1_SCK_F_MARK, +}; +static const unsigned int msiof1_sync_f_pins[] = { + /* SYNC */ + RCAR_GP_PIN(5, 24), +}; +static const unsigned int msiof1_sync_f_mux[] = { + MSIOF1_SYNC_F_MARK, +}; +static const unsigned int msiof1_ss1_f_pins[] = { + /* SS1 */ + RCAR_GP_PIN(6, 1), +}; +static const unsigned int msiof1_ss1_f_mux[] = { + MSIOF1_SS1_F_MARK, +}; +static const unsigned int msiof1_ss2_f_pins[] = { + /* SS2 */ + RCAR_GP_PIN(6, 2), +}; +static const unsigned int msiof1_ss2_f_mux[] = { + MSIOF1_SS2_F_MARK, +}; +static const unsigned int msiof1_txd_f_pins[] = { + /* TXD */ + RCAR_GP_PIN(6, 0), +}; +static const unsigned int msiof1_txd_f_mux[] = { + MSIOF1_TXD_F_MARK, +}; +static const unsigned int msiof1_rxd_f_pins[] = { + /* RXD */ + RCAR_GP_PIN(5, 25), +}; +static const unsigned int msiof1_rxd_f_mux[] = { + MSIOF1_RXD_F_MARK, +}; +static const unsigned int msiof1_clk_g_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 6), +}; +static const unsigned int msiof1_clk_g_mux[] = { + MSIOF1_SCK_G_MARK, +}; +static const unsigned int msiof1_sync_g_pins[] = { + /* SYNC */ + RCAR_GP_PIN(3, 7), +}; +static const unsigned int msiof1_sync_g_mux[] = { + MSIOF1_SYNC_G_MARK, +}; +static const unsigned int msiof1_ss1_g_pins[] = { + /* SS1 */ + RCAR_GP_PIN(3, 10), +}; +static const unsigned int msiof1_ss1_g_mux[] = { + MSIOF1_SS1_G_MARK, +}; +static const unsigned int msiof1_ss2_g_pins[] = { + /* SS2 */ + RCAR_GP_PIN(3, 11), +}; +static const unsigned int msiof1_ss2_g_mux[] = { + MSIOF1_SS2_G_MARK, +}; +static const unsigned int msiof1_txd_g_pins[] = { + /* TXD */ + RCAR_GP_PIN(3, 9), +}; +static const unsigned int msiof1_txd_g_mux[] = { + MSIOF1_TXD_G_MARK, +}; +static const unsigned int msiof1_rxd_g_pins[] = { + /* RXD */ + RCAR_GP_PIN(3, 8), +}; +static const unsigned int msiof1_rxd_g_mux[] = { + MSIOF1_RXD_G_MARK, +}; +/* - MSIOF2 ----------------------------------------------------------------- */ +static const unsigned int msiof2_clk_a_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 9), +}; +static const unsigned int msiof2_clk_a_mux[] = { + MSIOF2_SCK_A_MARK, +}; +static const unsigned int msiof2_sync_a_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 8), +}; +static const unsigned int msiof2_sync_a_mux[] = { + MSIOF2_SYNC_A_MARK, +}; +static const unsigned int msiof2_ss1_a_pins[] = { + /* SS1 */ + RCAR_GP_PIN(1, 6), +}; +static const unsigned int msiof2_ss1_a_mux[] = { + MSIOF2_SS1_A_MARK, +}; +static const unsigned int msiof2_ss2_a_pins[] = { + /* SS2 */ + RCAR_GP_PIN(1, 7), +}; +static const unsigned int msiof2_ss2_a_mux[] = { + MSIOF2_SS2_A_MARK, +}; +static const unsigned int msiof2_txd_a_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 11), +}; +static const unsigned int msiof2_txd_a_mux[] = { + MSIOF2_TXD_A_MARK, +}; +static const unsigned int msiof2_rxd_a_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 10), +}; +static const unsigned int msiof2_rxd_a_mux[] = { + MSIOF2_RXD_A_MARK, +}; +static const unsigned int msiof2_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(0, 4), +}; +static const unsigned int msiof2_clk_b_mux[] = { + MSIOF2_SCK_B_MARK, +}; +static const unsigned int msiof2_sync_b_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 5), +}; +static const unsigned int msiof2_sync_b_mux[] = { + MSIOF2_SYNC_B_MARK, +}; +static const unsigned int msiof2_ss1_b_pins[] = { + /* SS1 */ + RCAR_GP_PIN(0, 0), +}; +static const unsigned int msiof2_ss1_b_mux[] = { + MSIOF2_SS1_B_MARK, +}; +static const unsigned int msiof2_ss2_b_pins[] = { + /* SS2 */ + RCAR_GP_PIN(0, 1), +}; +static const unsigned int msiof2_ss2_b_mux[] = { + MSIOF2_SS2_B_MARK, +}; +static const unsigned int msiof2_txd_b_pins[] = { + /* TXD */ + RCAR_GP_PIN(0, 7), +}; +static const unsigned int msiof2_txd_b_mux[] = { + MSIOF2_TXD_B_MARK, +}; +static const unsigned int msiof2_rxd_b_pins[] = { + /* RXD */ + RCAR_GP_PIN(0, 6), +}; +static const unsigned int msiof2_rxd_b_mux[] = { + MSIOF2_RXD_B_MARK, +}; +static const unsigned int msiof2_clk_c_pins[] = { + /* SCK */ + RCAR_GP_PIN(2, 12), +}; +static const unsigned int msiof2_clk_c_mux[] = { + MSIOF2_SCK_C_MARK, +}; +static const unsigned int msiof2_sync_c_pins[] = { + /* SYNC */ + RCAR_GP_PIN(2, 11), +}; +static const unsigned int msiof2_sync_c_mux[] = { + MSIOF2_SYNC_C_MARK, +}; +static const unsigned int msiof2_ss1_c_pins[] = { + /* SS1 */ + RCAR_GP_PIN(2, 10), +}; +static const unsigned int msiof2_ss1_c_mux[] = { + MSIOF2_SS1_C_MARK, +}; +static const unsigned int msiof2_ss2_c_pins[] = { + /* SS2 */ + RCAR_GP_PIN(2, 9), +}; +static const unsigned int msiof2_ss2_c_mux[] = { + MSIOF2_SS2_C_MARK, +}; +static const unsigned int msiof2_txd_c_pins[] = { + /* TXD */ + RCAR_GP_PIN(2, 14), +}; +static const unsigned int msiof2_txd_c_mux[] = { + MSIOF2_TXD_C_MARK, +}; +static const unsigned int msiof2_rxd_c_pins[] = { + /* RXD */ + RCAR_GP_PIN(2, 13), +}; +static const unsigned int msiof2_rxd_c_mux[] = { + MSIOF2_RXD_C_MARK, +}; +static const unsigned int msiof2_clk_d_pins[] = { + /* SCK */ + RCAR_GP_PIN(0, 8), +}; +static const unsigned int msiof2_clk_d_mux[] = { + MSIOF2_SCK_D_MARK, +}; +static const unsigned int msiof2_sync_d_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 9), +}; +static const unsigned int msiof2_sync_d_mux[] = { + MSIOF2_SYNC_D_MARK, +}; +static const unsigned int msiof2_ss1_d_pins[] = { + /* SS1 */ + RCAR_GP_PIN(0, 12), +}; +static const unsigned int msiof2_ss1_d_mux[] = { + MSIOF2_SS1_D_MARK, +}; +static const unsigned int msiof2_ss2_d_pins[] = { + /* SS2 */ + RCAR_GP_PIN(0, 13), +}; +static const unsigned int msiof2_ss2_d_mux[] = { + MSIOF2_SS2_D_MARK, +}; +static const unsigned int msiof2_txd_d_pins[] = { + /* TXD */ + RCAR_GP_PIN(0, 11), +}; +static const unsigned int msiof2_txd_d_mux[] = { + MSIOF2_TXD_D_MARK, +}; +static const unsigned int msiof2_rxd_d_pins[] = { + /* RXD */ + RCAR_GP_PIN(0, 10), +}; +static const unsigned int msiof2_rxd_d_mux[] = { + MSIOF2_RXD_D_MARK, +}; +/* - MSIOF3 ----------------------------------------------------------------- */ +static const unsigned int msiof3_clk_a_pins[] = { + /* SCK */ + RCAR_GP_PIN(0, 0), +}; +static const unsigned int msiof3_clk_a_mux[] = { + MSIOF3_SCK_A_MARK, +}; +static const unsigned int msiof3_sync_a_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 1), +}; +static const unsigned int msiof3_sync_a_mux[] = { + MSIOF3_SYNC_A_MARK, +}; +static const unsigned int msiof3_ss1_a_pins[] = { + /* SS1 */ + RCAR_GP_PIN(0, 14), +}; +static const unsigned int msiof3_ss1_a_mux[] = { + MSIOF3_SS1_A_MARK, +}; +static const unsigned int msiof3_ss2_a_pins[] = { + /* SS2 */ + RCAR_GP_PIN(0, 15), +}; +static const unsigned int msiof3_ss2_a_mux[] = { + MSIOF3_SS2_A_MARK, +}; +static const unsigned int msiof3_txd_a_pins[] = { + /* TXD */ + RCAR_GP_PIN(0, 3), +}; +static const unsigned int msiof3_txd_a_mux[] = { + MSIOF3_TXD_A_MARK, +}; +static const unsigned int msiof3_rxd_a_pins[] = { + /* RXD */ + RCAR_GP_PIN(0, 2), +}; +static const unsigned int msiof3_rxd_a_mux[] = { + MSIOF3_RXD_A_MARK, +}; +static const unsigned int msiof3_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 2), +}; +static const unsigned int msiof3_clk_b_mux[] = { + MSIOF3_SCK_B_MARK, +}; +static const unsigned int msiof3_sync_b_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 0), +}; +static const unsigned int msiof3_sync_b_mux[] = { + MSIOF3_SYNC_B_MARK, +}; +static const unsigned int msiof3_ss1_b_pins[] = { + /* SS1 */ + RCAR_GP_PIN(1, 4), +}; +static const unsigned int msiof3_ss1_b_mux[] = { + MSIOF3_SS1_B_MARK, +}; +static const unsigned int msiof3_ss2_b_pins[] = { + /* SS2 */ + RCAR_GP_PIN(1, 5), +}; +static const unsigned int msiof3_ss2_b_mux[] = { + MSIOF3_SS2_B_MARK, +}; +static const unsigned int msiof3_txd_b_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 1), +}; +static const unsigned int msiof3_txd_b_mux[] = { + MSIOF3_TXD_B_MARK, +}; +static const unsigned int msiof3_rxd_b_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 3), +}; +static const unsigned int msiof3_rxd_b_mux[] = { + MSIOF3_RXD_B_MARK, +}; +static const unsigned int msiof3_clk_c_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 12), +}; +static const unsigned int msiof3_clk_c_mux[] = { + MSIOF3_SCK_C_MARK, +}; +static const unsigned int msiof3_sync_c_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 13), +}; +static const unsigned int msiof3_sync_c_mux[] = { + MSIOF3_SYNC_C_MARK, +}; +static const unsigned int msiof3_txd_c_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 15), +}; +static const unsigned int msiof3_txd_c_mux[] = { + MSIOF3_TXD_C_MARK, +}; +static const unsigned int msiof3_rxd_c_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 14), +}; +static const unsigned int msiof3_rxd_c_mux[] = { + MSIOF3_RXD_C_MARK, +}; +static const unsigned int msiof3_clk_d_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 22), +}; +static const unsigned int msiof3_clk_d_mux[] = { + MSIOF3_SCK_D_MARK, +}; +static const unsigned int msiof3_sync_d_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 23), +}; +static const unsigned int msiof3_sync_d_mux[] = { + MSIOF3_SYNC_D_MARK, +}; +static const unsigned int msiof3_ss1_d_pins[] = { + /* SS1 */ + RCAR_GP_PIN(1, 26), +}; +static const unsigned int msiof3_ss1_d_mux[] = { + MSIOF3_SS1_D_MARK, +}; +static const unsigned int msiof3_txd_d_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 25), +}; +static const unsigned int msiof3_txd_d_mux[] = { + MSIOF3_TXD_D_MARK, +}; +static const unsigned int msiof3_rxd_d_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 24), +}; +static const unsigned int msiof3_rxd_d_mux[] = { + MSIOF3_RXD_D_MARK, +}; + +static const unsigned int msiof3_clk_e_pins[] = { + /* SCK */ + RCAR_GP_PIN(2, 3), +}; +static const unsigned int msiof3_clk_e_mux[] = { + MSIOF3_SCK_E_MARK, +}; +static const unsigned int msiof3_sync_e_pins[] = { + /* SYNC */ + RCAR_GP_PIN(2, 2), +}; +static const unsigned int msiof3_sync_e_mux[] = { + MSIOF3_SYNC_E_MARK, +}; +static const unsigned int msiof3_ss1_e_pins[] = { + /* SS1 */ + RCAR_GP_PIN(2, 1), +}; +static const unsigned int msiof3_ss1_e_mux[] = { + MSIOF3_SS1_E_MARK, +}; +static const unsigned int msiof3_ss2_e_pins[] = { + /* SS1 */ + RCAR_GP_PIN(2, 0), +}; +static const unsigned int msiof3_ss2_e_mux[] = { + MSIOF3_SS1_E_MARK, +}; +static const unsigned int msiof3_txd_e_pins[] = { + /* TXD */ + RCAR_GP_PIN(2, 5), +}; +static const unsigned int msiof3_txd_e_mux[] = { + MSIOF3_TXD_E_MARK, +}; +static const unsigned int msiof3_rxd_e_pins[] = { + /* RXD */ + RCAR_GP_PIN(2, 4), +}; +static const unsigned int msiof3_rxd_e_mux[] = { + MSIOF3_RXD_E_MARK, +}; + /* - SCIF0 ------------------------------------------------------------------ */ static const unsigned int scif0_data_pins[] = { /* RX, TX */ @@ -2532,6 +3231,105 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(i2c6_a), SH_PFC_PIN_GROUP(i2c6_b), SH_PFC_PIN_GROUP(i2c6_c), + SH_PFC_PIN_GROUP(msiof0_clk), + SH_PFC_PIN_GROUP(msiof0_sync), + SH_PFC_PIN_GROUP(msiof0_ss1), + SH_PFC_PIN_GROUP(msiof0_ss2), + SH_PFC_PIN_GROUP(msiof0_txd), + SH_PFC_PIN_GROUP(msiof0_rxd), + SH_PFC_PIN_GROUP(msiof1_clk_a), + SH_PFC_PIN_GROUP(msiof1_sync_a), + SH_PFC_PIN_GROUP(msiof1_ss1_a), + SH_PFC_PIN_GROUP(msiof1_ss2_a), + SH_PFC_PIN_GROUP(msiof1_txd_a), + SH_PFC_PIN_GROUP(msiof1_rxd_a), + SH_PFC_PIN_GROUP(msiof1_clk_b), + SH_PFC_PIN_GROUP(msiof1_sync_b), + SH_PFC_PIN_GROUP(msiof1_ss1_b), + SH_PFC_PIN_GROUP(msiof1_ss2_b), + SH_PFC_PIN_GROUP(msiof1_txd_b), + SH_PFC_PIN_GROUP(msiof1_rxd_b), + SH_PFC_PIN_GROUP(msiof1_clk_c), + SH_PFC_PIN_GROUP(msiof1_sync_c), + SH_PFC_PIN_GROUP(msiof1_ss1_c), + SH_PFC_PIN_GROUP(msiof1_ss2_c), + SH_PFC_PIN_GROUP(msiof1_txd_c), + SH_PFC_PIN_GROUP(msiof1_rxd_c), + SH_PFC_PIN_GROUP(msiof1_clk_d), + SH_PFC_PIN_GROUP(msiof1_sync_d), + SH_PFC_PIN_GROUP(msiof1_ss1_d), + SH_PFC_PIN_GROUP(msiof1_ss2_d), + SH_PFC_PIN_GROUP(msiof1_txd_d), + SH_PFC_PIN_GROUP(msiof1_rxd_d), + SH_PFC_PIN_GROUP(msiof1_clk_e), + SH_PFC_PIN_GROUP(msiof1_sync_e), + SH_PFC_PIN_GROUP(msiof1_ss1_e), + SH_PFC_PIN_GROUP(msiof1_ss2_e), + SH_PFC_PIN_GROUP(msiof1_txd_e), + SH_PFC_PIN_GROUP(msiof1_rxd_e), + SH_PFC_PIN_GROUP(msiof1_clk_f), + SH_PFC_PIN_GROUP(msiof1_sync_f), + SH_PFC_PIN_GROUP(msiof1_ss1_f), + SH_PFC_PIN_GROUP(msiof1_ss2_f), + SH_PFC_PIN_GROUP(msiof1_txd_f), + SH_PFC_PIN_GROUP(msiof1_rxd_f), + SH_PFC_PIN_GROUP(msiof1_clk_g), + SH_PFC_PIN_GROUP(msiof1_sync_g), + SH_PFC_PIN_GROUP(msiof1_ss1_g), + SH_PFC_PIN_GROUP(msiof1_ss2_g), + SH_PFC_PIN_GROUP(msiof1_txd_g), + SH_PFC_PIN_GROUP(msiof1_rxd_g), + SH_PFC_PIN_GROUP(msiof2_clk_a), + SH_PFC_PIN_GROUP(msiof2_sync_a), + SH_PFC_PIN_GROUP(msiof2_ss1_a), + SH_PFC_PIN_GROUP(msiof2_ss2_a), + SH_PFC_PIN_GROUP(msiof2_txd_a), + SH_PFC_PIN_GROUP(msiof2_rxd_a), + SH_PFC_PIN_GROUP(msiof2_clk_b), + SH_PFC_PIN_GROUP(msiof2_sync_b), + SH_PFC_PIN_GROUP(msiof2_ss1_b), + SH_PFC_PIN_GROUP(msiof2_ss2_b), + SH_PFC_PIN_GROUP(msiof2_txd_b), + SH_PFC_PIN_GROUP(msiof2_rxd_b), + SH_PFC_PIN_GROUP(msiof2_clk_c), + SH_PFC_PIN_GROUP(msiof2_sync_c), + SH_PFC_PIN_GROUP(msiof2_ss1_c), + SH_PFC_PIN_GROUP(msiof2_ss2_c), + SH_PFC_PIN_GROUP(msiof2_txd_c), + SH_PFC_PIN_GROUP(msiof2_rxd_c), + SH_PFC_PIN_GROUP(msiof2_clk_d), + SH_PFC_PIN_GROUP(msiof2_sync_d), + SH_PFC_PIN_GROUP(msiof2_ss1_d), + SH_PFC_PIN_GROUP(msiof2_ss2_d), + SH_PFC_PIN_GROUP(msiof2_txd_d), + SH_PFC_PIN_GROUP(msiof2_rxd_d), + SH_PFC_PIN_GROUP(msiof3_clk_a), + SH_PFC_PIN_GROUP(msiof3_sync_a), + SH_PFC_PIN_GROUP(msiof3_ss1_a), + SH_PFC_PIN_GROUP(msiof3_ss2_a), + SH_PFC_PIN_GROUP(msiof3_txd_a), + SH_PFC_PIN_GROUP(msiof3_rxd_a), + SH_PFC_PIN_GROUP(msiof3_clk_b), + SH_PFC_PIN_GROUP(msiof3_sync_b), + SH_PFC_PIN_GROUP(msiof3_ss1_b), + SH_PFC_PIN_GROUP(msiof3_ss2_b), + SH_PFC_PIN_GROUP(msiof3_txd_b), + SH_PFC_PIN_GROUP(msiof3_rxd_b), + SH_PFC_PIN_GROUP(msiof3_clk_c), + SH_PFC_PIN_GROUP(msiof3_sync_c), + SH_PFC_PIN_GROUP(msiof3_txd_c), + SH_PFC_PIN_GROUP(msiof3_rxd_c), + SH_PFC_PIN_GROUP(msiof3_clk_d), + SH_PFC_PIN_GROUP(msiof3_sync_d), + SH_PFC_PIN_GROUP(msiof3_ss1_d), + SH_PFC_PIN_GROUP(msiof3_txd_d), + SH_PFC_PIN_GROUP(msiof3_rxd_d), + SH_PFC_PIN_GROUP(msiof3_clk_e), + SH_PFC_PIN_GROUP(msiof3_sync_e), + SH_PFC_PIN_GROUP(msiof3_ss1_e), + SH_PFC_PIN_GROUP(msiof3_ss2_e), + SH_PFC_PIN_GROUP(msiof3_txd_e), + SH_PFC_PIN_GROUP(msiof3_rxd_e), SH_PFC_PIN_GROUP(scif0_data), SH_PFC_PIN_GROUP(scif0_clk), SH_PFC_PIN_GROUP(scif0_ctrl), @@ -2692,6 +3490,117 @@ static const char * const i2c6_groups[] = { "i2c6_c", }; +static const char * const msiof0_groups[] = { + "msiof0_clk", + "msiof0_sync", + "msiof0_ss1", + "msiof0_ss2", + "msiof0_txd", + "msiof0_rxd", +}; + +static const char * const msiof1_groups[] = { + "msiof1_clk_a", + "msiof1_sync_a", + "msiof1_ss1_a", + "msiof1_ss2_a", + "msiof1_txd_a", + "msiof1_rxd_a", + "msiof1_clk_b", + "msiof1_sync_b", + "msiof1_ss1_b", + "msiof1_ss2_b", + "msiof1_txd_b", + "msiof1_rxd_b", + "msiof1_clk_c", + "msiof1_sync_c", + "msiof1_ss1_c", + "msiof1_ss2_c", + "msiof1_txd_c", + "msiof1_rxd_c", + "msiof1_clk_d", + "msiof1_sync_d", + "msiof1_ss1_d", + "msiof1_ss2_d", + "msiof1_txd_d", + "msiof1_rxd_d", + "msiof1_clk_e", + "msiof1_sync_e", + "msiof1_ss1_e", + "msiof1_ss2_e", + "msiof1_txd_e", + "msiof1_rxd_e", + "msiof1_clk_f", + "msiof1_sync_f", + "msiof1_ss1_f", + "msiof1_ss2_f", + "msiof1_txd_f", + "msiof1_rxd_f", + "msiof1_clk_g", + "msiof1_sync_g", + "msiof1_ss1_g", + "msiof1_ss2_g", + "msiof1_txd_g", + "msiof1_rxd_g", +}; + +static const char * const msiof2_groups[] = { + "msiof2_clk_a", + "msiof2_sync_a", + "msiof2_ss1_a", + "msiof2_ss2_a", + "msiof2_txd_a", + "msiof2_rxd_a", + "msiof2_clk_b", + "msiof2_sync_b", + "msiof2_ss1_b", + "msiof2_ss2_b", + "msiof2_txd_b", + "msiof2_rxd_b", + "msiof2_clk_c", + "msiof2_sync_c", + "msiof2_ss1_c", + "msiof2_ss2_c", + "msiof2_txd_c", + "msiof2_rxd_c", + "msiof2_clk_d", + "msiof2_sync_d", + "msiof2_ss1_d", + "msiof2_ss2_d", + "msiof2_txd_d", + "msiof2_rxd_d", +}; + +static const char * const msiof3_groups[] = { + "msiof3_clk_a", + "msiof3_sync_a", + "msiof3_ss1_a", + "msiof3_ss2_a", + "msiof3_txd_a", + "msiof3_rxd_a", + "msiof3_clk_b", + "msiof3_sync_b", + "msiof3_ss1_b", + "msiof3_ss2_b", + "msiof3_txd_b", + "msiof3_rxd_b", + "msiof3_clk_c", + "msiof3_sync_c", + "msiof3_txd_c", + "msiof3_rxd_c", + "msiof3_clk_d", + "msiof3_sync_d", + "msiof3_ss1_d", + "msiof3_txd_d", + "msiof3_rxd_d", + "msiof3_clk_e", + "msiof3_sync_e", + "msiof3_ss1_e", + "msiof3_ss2_e", + "msiof3_txd_e", + "msiof3_rxd_e", +}; + static const char * const scif0_groups[] = { "scif0_data", "scif0_clk", @@ -2795,6 +3704,10 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(i2c1), SH_PFC_FUNCTION(i2c2), SH_PFC_FUNCTION(i2c6), + SH_PFC_FUNCTION(msiof0), + SH_PFC_FUNCTION(msiof1), + SH_PFC_FUNCTION(msiof2), + SH_PFC_FUNCTION(msiof3), SH_PFC_FUNCTION(scif0), SH_PFC_FUNCTION(scif1), SH_PFC_FUNCTION(scif2), From aa6931f135d293cf6b0d527360845ff38455bc72 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 1 Dec 2016 14:21:07 +0100 Subject: [PATCH 0021/1587] pinctrl: sh-pfc: r8a7793: Implement voltage switching for SDHI Voltage switching is the same as on the r8a7791. Signed-off-by: Simon Horman Reviewed-by: Wolfram Sang Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 7ca37c3019ab..e8de975b3a58 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -6455,6 +6455,7 @@ const struct sh_pfc_soc_info r8a7791_pinmux_info = { #ifdef CONFIG_PINCTRL_PFC_R8A7793 const struct sh_pfc_soc_info r8a7793_pinmux_info = { .name = "r8a77930_pfc", + .ops = &r8a7791_pinmux_ops, .unlock_reg = 0xe6060000, /* PMMR */ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, From 0e4e4999aac16641f47699e8929693b83a7a4d64 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Wed, 7 Dec 2016 17:44:46 +0100 Subject: [PATCH 0022/1587] pinctrl: sh-pfc: r8a7796: Add HSCIF pins, groups, and functions Signed-off-by: Ulrich Hecht [geert: Fix hscif2_clk_[bc]_mux[] and hscif4_ctrl_mux[]] Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7796.c | 283 +++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 34a05d774172..b0362ae707e2 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -1998,6 +1998,213 @@ static const unsigned int du_disp_mux[] = { DU_DISP_MARK, }; +/* - HSCIF0 ----------------------------------------------------------------- */ +static const unsigned int hscif0_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 14), +}; +static const unsigned int hscif0_data_mux[] = { + HRX0_MARK, HTX0_MARK, +}; +static const unsigned int hscif0_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 12), +}; +static const unsigned int hscif0_clk_mux[] = { + HSCK0_MARK, +}; +static const unsigned int hscif0_ctrl_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(5, 16), RCAR_GP_PIN(5, 15), +}; +static const unsigned int hscif0_ctrl_mux[] = { + HRTS0_N_MARK, HCTS0_N_MARK, +}; +/* - HSCIF1 ----------------------------------------------------------------- */ +static const unsigned int hscif1_data_a_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 6), +}; +static const unsigned int hscif1_data_a_mux[] = { + HRX1_A_MARK, HTX1_A_MARK, +}; +static const unsigned int hscif1_clk_a_pins[] = { + /* SCK */ + RCAR_GP_PIN(6, 21), +}; +static const unsigned int hscif1_clk_a_mux[] = { + HSCK1_A_MARK, +}; +static const unsigned int hscif1_ctrl_a_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 7), +}; +static const unsigned int hscif1_ctrl_a_mux[] = { + HRTS1_N_A_MARK, HCTS1_N_A_MARK, +}; + +static const unsigned int hscif1_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2), +}; +static const unsigned int hscif1_data_b_mux[] = { + HRX1_B_MARK, HTX1_B_MARK, +}; +static const unsigned int hscif1_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 0), +}; +static const unsigned int hscif1_clk_b_mux[] = { + HSCK1_B_MARK, +}; +static const unsigned int hscif1_ctrl_b_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 3), +}; +static const unsigned int hscif1_ctrl_b_mux[] = { + HRTS1_N_B_MARK, HCTS1_N_B_MARK, +}; +/* - HSCIF2 ----------------------------------------------------------------- */ +static const unsigned int hscif2_data_a_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9), +}; +static const unsigned int hscif2_data_a_mux[] = { + HRX2_A_MARK, HTX2_A_MARK, +}; +static const unsigned int hscif2_clk_a_pins[] = { + /* SCK */ + RCAR_GP_PIN(6, 10), +}; +static const unsigned int hscif2_clk_a_mux[] = { + HSCK2_A_MARK, +}; +static const unsigned int hscif2_ctrl_a_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 6), +}; +static const unsigned int hscif2_ctrl_a_mux[] = { + HRTS2_N_A_MARK, HCTS2_N_A_MARK, +}; + +static const unsigned int hscif2_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18), +}; +static const unsigned int hscif2_data_b_mux[] = { + HRX2_B_MARK, HTX2_B_MARK, +}; +static const unsigned int hscif2_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(6, 21), +}; +static const unsigned int hscif2_clk_b_mux[] = { + HSCK2_B_MARK, +}; +static const unsigned int hscif2_ctrl_b_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 19), +}; +static const unsigned int hscif2_ctrl_b_mux[] = { + HRTS2_N_B_MARK, HCTS2_N_B_MARK, +}; + +static const unsigned int hscif2_data_c_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(6, 25), RCAR_GP_PIN(6, 26), +}; +static const unsigned int hscif2_data_c_mux[] = { + HRX2_C_MARK, HTX2_C_MARK, +}; +static const unsigned int hscif2_clk_c_pins[] = { + /* SCK */ + RCAR_GP_PIN(6, 24), +}; +static const unsigned int hscif2_clk_c_mux[] = { + HSCK2_C_MARK, +}; +static const unsigned int hscif2_ctrl_c_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 27), +}; +static const unsigned int hscif2_ctrl_c_mux[] = { + HRTS2_N_C_MARK, HCTS2_N_C_MARK, +}; +/* - HSCIF3 ----------------------------------------------------------------- */ +static const unsigned int hscif3_data_a_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), +}; +static const unsigned int hscif3_data_a_mux[] = { + HRX3_A_MARK, HTX3_A_MARK, +}; +static const unsigned int hscif3_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 22), +}; +static const unsigned int hscif3_clk_mux[] = { + HSCK3_MARK, +}; +static const unsigned int hscif3_ctrl_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25), +}; +static const unsigned int hscif3_ctrl_mux[] = { + HRTS3_N_MARK, HCTS3_N_MARK, +}; + +static const unsigned int hscif3_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11), +}; +static const unsigned int hscif3_data_b_mux[] = { + HRX3_B_MARK, HTX3_B_MARK, +}; +static const unsigned int hscif3_data_c_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15), +}; +static const unsigned int hscif3_data_c_mux[] = { + HRX3_C_MARK, HTX3_C_MARK, +}; +static const unsigned int hscif3_data_d_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8), +}; +static const unsigned int hscif3_data_d_mux[] = { + HRX3_D_MARK, HTX3_D_MARK, +}; +/* - HSCIF4 ----------------------------------------------------------------- */ +static const unsigned int hscif4_data_a_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 13), +}; +static const unsigned int hscif4_data_a_mux[] = { + HRX4_A_MARK, HTX4_A_MARK, +}; +static const unsigned int hscif4_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 11), +}; +static const unsigned int hscif4_clk_mux[] = { + HSCK4_MARK, +}; +static const unsigned int hscif4_ctrl_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14), +}; +static const unsigned int hscif4_ctrl_mux[] = { + HRTS4_N_MARK, HCTS4_N_MARK, +}; + +static const unsigned int hscif4_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 11), +}; +static const unsigned int hscif4_data_b_mux[] = { + HRX4_B_MARK, HTX4_B_MARK, +}; + /* - I2C -------------------------------------------------------------------- */ static const unsigned int i2c1_a_pins[] = { /* SDA, SCL */ @@ -3224,6 +3431,34 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(du_oddf), SH_PFC_PIN_GROUP(du_cde), SH_PFC_PIN_GROUP(du_disp), + SH_PFC_PIN_GROUP(hscif0_data), + SH_PFC_PIN_GROUP(hscif0_clk), + SH_PFC_PIN_GROUP(hscif0_ctrl), + SH_PFC_PIN_GROUP(hscif1_data_a), + SH_PFC_PIN_GROUP(hscif1_clk_a), + SH_PFC_PIN_GROUP(hscif1_ctrl_a), + SH_PFC_PIN_GROUP(hscif1_data_b), + SH_PFC_PIN_GROUP(hscif1_clk_b), + SH_PFC_PIN_GROUP(hscif1_ctrl_b), + SH_PFC_PIN_GROUP(hscif2_data_a), + SH_PFC_PIN_GROUP(hscif2_clk_a), + SH_PFC_PIN_GROUP(hscif2_ctrl_a), + SH_PFC_PIN_GROUP(hscif2_data_b), + SH_PFC_PIN_GROUP(hscif2_clk_b), + SH_PFC_PIN_GROUP(hscif2_ctrl_b), + SH_PFC_PIN_GROUP(hscif2_data_c), + SH_PFC_PIN_GROUP(hscif2_clk_c), + SH_PFC_PIN_GROUP(hscif2_ctrl_c), + SH_PFC_PIN_GROUP(hscif3_data_a), + SH_PFC_PIN_GROUP(hscif3_clk), + SH_PFC_PIN_GROUP(hscif3_ctrl), + SH_PFC_PIN_GROUP(hscif3_data_b), + SH_PFC_PIN_GROUP(hscif3_data_c), + SH_PFC_PIN_GROUP(hscif3_data_d), + SH_PFC_PIN_GROUP(hscif4_data_a), + SH_PFC_PIN_GROUP(hscif4_clk), + SH_PFC_PIN_GROUP(hscif4_ctrl), + SH_PFC_PIN_GROUP(hscif4_data_b), SH_PFC_PIN_GROUP(i2c1_a), SH_PFC_PIN_GROUP(i2c1_b), SH_PFC_PIN_GROUP(i2c2_a), @@ -3474,6 +3709,49 @@ static const char * const du_groups[] = { "du_disp", }; +static const char * const hscif0_groups[] = { + "hscif0_data", + "hscif0_clk", + "hscif0_ctrl", +}; + +static const char * const hscif1_groups[] = { + "hscif1_data_a", + "hscif1_clk_a", + "hscif1_ctrl_a", + "hscif1_data_b", + "hscif1_clk_b", + "hscif1_ctrl_b", +}; + +static const char * const hscif2_groups[] = { + "hscif2_data_a", + "hscif2_clk_a", + "hscif2_ctrl_a", + "hscif2_data_b", + "hscif2_clk_b", + "hscif2_ctrl_b", + "hscif2_data_c", + "hscif2_clk_c", + "hscif2_ctrl_c", +}; + +static const char * const hscif3_groups[] = { + "hscif3_data_a", + "hscif3_clk", + "hscif3_ctrl", + "hscif3_data_b", + "hscif3_data_c", + "hscif3_data_d", +}; + +static const char * const hscif4_groups[] = { + "hscif4_data_a", + "hscif4_clk", + "hscif4_ctrl", + "hscif4_data_b", +}; + static const char * const i2c1_groups[] = { "i2c1_a", "i2c1_b", @@ -3701,6 +3979,11 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(drif2), SH_PFC_FUNCTION(drif3), SH_PFC_FUNCTION(du), + SH_PFC_FUNCTION(hscif0), + SH_PFC_FUNCTION(hscif1), + SH_PFC_FUNCTION(hscif2), + SH_PFC_FUNCTION(hscif3), + SH_PFC_FUNCTION(hscif4), SH_PFC_FUNCTION(i2c1), SH_PFC_FUNCTION(i2c2), SH_PFC_FUNCTION(i2c6), From 40eca140c404505c09773d1c6685d818cb55ab1a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 14 Feb 2016 00:41:06 -0200 Subject: [PATCH 0023/1587] [media] mn88473: add DVB-T2 PLP support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds PLP ID filtering for DVB-T2. It is untested as I don't have any signal having PLP ID other than 0. There is only 2 extra registers, 0x32 and 0x36 on bank2, that are programmed for DVB-T2 but not for DVB-T and all the rest are programmed similarly - so it is likely PLP. Pridvorov reported successfully testing it in Russia with m-PLP streams, on both Vladivostok and Moskow. Tested-by: "Придворов Андрей (Pridvorov Andrey)" Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mn88473.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c index c221c7d2ac3e..15874244fd8b 100644 --- a/drivers/media/dvb-frontends/mn88473.c +++ b/drivers/media/dvb-frontends/mn88473.c @@ -223,6 +223,13 @@ static int mn88473_set_frontend(struct dvb_frontend *fe) if (ret) goto err; + /* PLP */ + if (c->delivery_system == SYS_DVBT2) { + ret = regmap_write(dev->regmap[2], 0x36, c->stream_id); + if (ret) + goto err; + } + /* Reset FSM */ ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); if (ret) @@ -592,7 +599,8 @@ static const struct dvb_frontend_ops mn88473_ops = { FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_MUTE_TS | - FE_CAN_2G_MODULATION + FE_CAN_2G_MODULATION | + FE_CAN_MULTISTREAM }, .get_tune_settings = mn88473_get_tune_settings, From c95b0fec3cff0ba584fd2f9e71fd9001ad15381a Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Tue, 20 Dec 2016 18:05:47 +1030 Subject: [PATCH 0024/1587] pinctrl: aspeed: dt: Fix compatibles for the System Control Unit Reference the SoC-specific compatible string in the examples as required. Signed-off-by: Andrew Jeffery Acked-by: Joel Stanley Acked-by: Rob Herring Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/pinctrl-aspeed.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt index 2ad18c4ea55c..b2efb73337c6 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt @@ -11,9 +11,14 @@ Required properties: "aspeed,ast2500-pinctrl" "aspeed,g5-pinctrl" -The pin controller node should be a child of a syscon node with the required +The pin controller node should be the child of a syscon node with the required property: -- compatible: "syscon", "simple-mfd" + +- compatible : Should be one of the following: + "aspeed,ast2400-scu", "syscon", "simple-mfd" + "aspeed,g4-scu", "syscon", "simple-mfd" + "aspeed,ast2500-scu", "syscon", "simple-mfd" + "aspeed,g5-scu", "syscon", "simple-mfd" Refer to the the bindings described in Documentation/devicetree/bindings/mfd/syscon.txt @@ -50,7 +55,7 @@ TIMER7 TIMER8 VGABIOSROM Examples: syscon: scu@1e6e2000 { - compatible = "syscon", "simple-mfd"; + compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd"; reg = <0x1e6e2000 0x1a8>; pinctrl: pinctrl { From 7d29ed88acbbf00e2056634bd4c0172d55d2568c Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Tue, 20 Dec 2016 18:05:48 +1030 Subject: [PATCH 0025/1587] pinctrl: aspeed: Read and write bits in LPC and GFX controllers The System Control Unit IP block in the Aspeed SoCs is typically where the pinmux configuration is found, but not always. A number of pins depend on state in one of LPC Host Control (LHC) or SoC Display Controller (GFX) IP blocks, so the Aspeed pinmux drivers should have the means to adjust these as necessary. We use syscon to cast a regmap over the GFX and LPC blocks, which is used as an arbitration layer between the relevant driver and the pinctrl subsystem. The regmaps are then exposed to the SoC-specific pinctrl drivers by phandles in the devicetree, and are selected during a mux request by querying a new 'ip' member in struct aspeed_sig_desc. Signed-off-by: Andrew Jeffery Reviewed-by: Joel Stanley Acked-by: Rob Herring Signed-off-by: Linus Walleij --- .../bindings/pinctrl/pinctrl-aspeed.txt | 80 ++++++++- drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 18 +- drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 48 +++++- drivers/pinctrl/aspeed/pinctrl-aspeed.c | 161 +++++++++++------- drivers/pinctrl/aspeed/pinctrl-aspeed.h | 32 +++- 5 files changed, 242 insertions(+), 97 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt index b2efb73337c6..fb7694ec033d 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt @@ -1,15 +1,23 @@ +====================== Aspeed Pin Controllers ----------------------- +====================== The Aspeed SoCs vary in functionality inside a generation but have a common mux device register layout. -Required properties: -- compatible : Should be any one of the following: - "aspeed,ast2400-pinctrl" - "aspeed,g4-pinctrl" - "aspeed,ast2500-pinctrl" - "aspeed,g5-pinctrl" +Required properties for g4: +- compatible : Should be one of the following: + "aspeed,ast2400-pinctrl" + "aspeed,g4-pinctrl" + +Required properties for g5: +- compatible : Should be one of the following: + "aspeed,ast2500-pinctrl" + "aspeed,g5-pinctrl" + +- aspeed,external-nodes: A cell of phandles to external controller nodes: + 0: compatible with "aspeed,ast2500-gfx", "syscon" + 1: compatible with "aspeed,ast2500-lhc", "syscon" The pin controller node should be the child of a syscon node with the required property: @@ -24,7 +32,7 @@ Refer to the the bindings described in Documentation/devicetree/bindings/mfd/syscon.txt Subnode Format --------------- +============== The required properties of child nodes are (as defined in pinctrl-bindings): - function @@ -51,8 +59,11 @@ I2C9 MAC1LINK MDIO1 MDIO2 OSCCLK PEWAKE PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 SPI1DEBUG SPI1PASSTHRU TIMER4 TIMER5 TIMER6 TIMER7 TIMER8 VGABIOSROM +Examples +======== -Examples: +g4 Example +---------- syscon: scu@1e6e2000 { compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd"; @@ -68,5 +79,56 @@ syscon: scu@1e6e2000 { }; }; +g5 Example +---------- + +ahb { + apb { + syscon: scu@1e6e2000 { + compatible = "aspeed,ast2500-scu", "syscon", "simple-mfd"; + reg = <0x1e6e2000 0x1a8>; + + pinctrl: pinctrl { + compatible = "aspeed,g5-pinctrl"; + aspeed,external-nodes = <&gfx &lhc>; + + pinctrl_i2c3_default: i2c3_default { + function = "I2C3"; + groups = "I2C3"; + }; + }; + }; + + gfx: display@1e6e6000 { + compatible = "aspeed,ast2500-gfx", "syscon"; + reg = <0x1e6e6000 0x1000>; + }; + }; + + lpc: lpc@1e789000 { + compatible = "aspeed,ast2500-lpc", "simple-mfd"; + reg = <0x1e789000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1e789000 0x1000>; + + lpc_host: lpc-host@80 { + compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon"; + reg = <0x80 0x1e0>; + reg-io-width = <4>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x80 0x1e0>; + + lhc: lhc@20 { + compatible = "aspeed,ast2500-lhc"; + reg = <0x20 0x24 0x48 0x8>; + }; + }; + }; +}; + Please refer to pinctrl-bindings.txt in this directory for details of the common pinctrl bindings used by client devices. diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c index a21b071ff290..558bd102416c 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c @@ -292,7 +292,7 @@ SSSF_PIN_DECL(U18, GPIOG7, FLWP, SIG_DESC_SET(SCU84, 7)); #define UART6_DESC SIG_DESC_SET(SCU90, 7) #define ROM16_DESC SIG_DESC_SET(SCU90, 6) #define FLASH_WIDE SIG_DESC_SET(HW_STRAP1, 4) -#define BOOT_SRC_NOR { HW_STRAP1, GENMASK(1, 0), 0, 0 } +#define BOOT_SRC_NOR { ASPEED_IP_SCU, HW_STRAP1, GENMASK(1, 0), 0, 0 } #define A8 56 SIG_EXPR_DECL(ROMD8, ROM16, ROM16_DESC); @@ -418,9 +418,9 @@ FUNC_GROUP_DECL(I2C8, G5, F3); #define U1 88 SSSF_PIN_DECL(U1, GPIOL0, NCTS1, SIG_DESC_SET(SCU84, 16)); -#define VPI18_DESC { SCU90, GENMASK(5, 4), 1, 0 } -#define VPI24_DESC { SCU90, GENMASK(5, 4), 2, 0 } -#define VPI30_DESC { SCU90, GENMASK(5, 4), 3, 0 } +#define VPI18_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 1, 0 } +#define VPI24_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 2, 0 } +#define VPI30_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 3, 0 } #define T5 89 #define T5_DESC SIG_DESC_SET(SCU84, 17) @@ -641,11 +641,11 @@ SSSF_PIN_DECL(Y22, GPIOR2, ROMCS3, SIG_DESC_SET(SCU88, 26)); #define U19 139 SSSF_PIN_DECL(U19, GPIOR3, ROMCS4, SIG_DESC_SET(SCU88, 27)); -#define VPOOFF0_DESC { SCU94, GENMASK(1, 0), 0, 0 } -#define VPO12_DESC { SCU94, GENMASK(1, 0), 1, 0 } -#define VPO24_DESC { SCU94, GENMASK(1, 0), 2, 0 } -#define VPOOFF1_DESC { SCU94, GENMASK(1, 0), 3, 0 } -#define VPO_OFF_12 { SCU94, 0x2, 0, 0 } +#define VPOOFF0_DESC { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 0, 0 } +#define VPO12_DESC { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 1, 0 } +#define VPO24_DESC { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 2, 0 } +#define VPOOFF1_DESC { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 3, 0 } +#define VPO_OFF_12 { ASPEED_IP_SCU, SCU94, 0x2, 0, 0 } #define VPO_24_OFF SIG_DESC_SET(SCU94, 1) #define V21 140 diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index 87b46390b695..c5c9a1b6fa1c 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -26,8 +27,8 @@ #define ASPEED_G5_NR_PINS 228 -#define COND1 { SCU90, BIT(6), 0, 0 } -#define COND2 { SCU94, GENMASK(1, 0), 0, 0 } +#define COND1 { ASPEED_IP_SCU, SCU90, BIT(6), 0, 0 } +#define COND2 { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 0, 0 } #define B14 0 SSSF_PIN_DECL(B14, GPIOA0, MAC1LINK, SIG_DESC_SET(SCU80, 0)); @@ -186,9 +187,12 @@ MS_PIN_DECL(C20, GPIOE1, NDCD3, GPIE0OUT); FUNC_GROUP_DECL(GPIE0, B20, C20); -#define SPI1_DESC { HW_STRAP1, GENMASK(13, 12), 1, 0 } -#define SPI1DEBUG_DESC { HW_STRAP1, GENMASK(13, 12), 2, 0 } -#define SPI1PASSTHRU_DESC { HW_STRAP1, GENMASK(13, 12), 3, 0 } +#define SPI1_DESC \ + { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 1, 0 } +#define SPI1DEBUG_DESC \ + { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 2, 0 } +#define SPI1PASSTHRU_DESC \ + { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 3, 0 } #define C18 64 SIG_EXPR_DECL(SYSCS, SPI1DEBUG, COND1, SPI1DEBUG_DESC); @@ -325,10 +329,11 @@ SS_PIN_DECL(R1, GPIOK7, SDA8); FUNC_GROUP_DECL(I2C8, P2, R1); -#define VPIOFF0_DESC { SCU90, GENMASK(5, 4), 0, 0 } -#define VPIOFF1_DESC { SCU90, GENMASK(5, 4), 1, 0 } -#define VPI24_DESC { SCU90, GENMASK(5, 4), 2, 0 } -#define VPIRSVD_DESC { SCU90, GENMASK(5, 4), 3, 0 } +#define VPIOFF0_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 0, 0 } +#define VPIOFF1_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 1, 0 } +#define VPI24_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 2, 0 } +#define VPIRSVD_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 3, 0 } + #define V2 104 #define V2_DESC SIG_DESC_SET(SCU88, 0) @@ -848,10 +853,35 @@ static struct pinctrl_desc aspeed_g5_pinctrl_desc = { static int aspeed_g5_pinctrl_probe(struct platform_device *pdev) { int i; + struct regmap *map; + struct device_node *node; for (i = 0; i < ARRAY_SIZE(aspeed_g5_pins); i++) aspeed_g5_pins[i].number = i; + node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 0); + map = syscon_node_to_regmap(node); + of_node_put(node); + if (IS_ERR(map)) { + dev_warn(&pdev->dev, "No GFX phandle found, some mux configurations may fail\n"); + map = NULL; + } + aspeed_g5_pinctrl_data.maps[ASPEED_IP_GFX] = map; + + node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 1); + if (node) { + map = syscon_node_to_regmap(node->parent); + if (IS_ERR(map)) { + dev_warn(&pdev->dev, "LHC parent is not a syscon, some mux configurations may fail\n"); + map = NULL; + } + } else { + dev_warn(&pdev->dev, "No LHC phandle found, some mux configurations may fail\n"); + map = NULL; + } + of_node_put(node); + aspeed_g5_pinctrl_data.maps[ASPEED_IP_LPC] = map; + return aspeed_pinctrl_probe(pdev, &aspeed_g5_pinctrl_desc, &aspeed_g5_pinctrl_data); } diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c index 49aeba912531..782c5c97f853 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c @@ -14,6 +14,12 @@ #include "../core.h" #include "pinctrl-aspeed.h" +static const char *const aspeed_pinmux_ips[] = { + [ASPEED_IP_SCU] = "SCU", + [ASPEED_IP_GFX] = "GFX", + [ASPEED_IP_LPC] = "LPC", +}; + int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) { struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); @@ -78,7 +84,8 @@ int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev, static inline void aspeed_sig_desc_print_val( const struct aspeed_sig_desc *desc, bool enable, u32 rv) { - pr_debug("SCU%x[0x%08x]=0x%x, got 0x%x from 0x%08x\n", desc->reg, + pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n", + aspeed_pinmux_ips[desc->ip], desc->reg, desc->mask, enable ? desc->enable : desc->disable, (rv & desc->mask) >> __ffs(desc->mask), rv); } @@ -88,10 +95,11 @@ static inline void aspeed_sig_desc_print_val( * * @desc: The signal descriptor of interest * @enabled: True to query the enabled state, false to query disabled state - * @regmap: The SCU regmap instance + * @regmap: The IP block's regmap instance * - * @return True if the descriptor's bitfield is configured to the state - * selected by @enabled, false otherwise + * @return 1 if the descriptor's bitfield is configured to the state + * selected by @enabled, 0 if not, and less than zero if an unrecoverable + * failure occurred * * Evaluation of descriptor state is non-trivial in that it is not a binary * outcome: The bitfields can be greater than one bit in size and thus can take @@ -99,14 +107,19 @@ static inline void aspeed_sig_desc_print_val( * descriptor (typically this means a different function to the one of interest * is enabled). Thus we must explicitly test for either condition as required. */ -static bool aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, +static int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, bool enabled, struct regmap *map) { + int ret; unsigned int raw; u32 want; - if (regmap_read(map, desc->reg, &raw) < 0) - return false; + if (!map) + return -ENODEV; + + ret = regmap_read(map, desc->reg, &raw); + if (ret) + return ret; aspeed_sig_desc_print_val(desc, enabled, raw); want = enabled ? desc->enable : desc->disable; @@ -119,10 +132,10 @@ static bool aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, * * @expr: An expression controlling the signal for a mux function on a pin * @enabled: True to query the enabled state, false to query disabled state - * @regmap: The SCU regmap instance + * @maps: The list of regmap instances * - * @return True if the expression composed by @enabled evaluates true, false - * otherwise + * @return 1 if the expression composed by @enabled evaluates true, 0 if not, + * and less than zero if an unrecoverable failure occurred. * * A mux function is enabled or disabled if the function's signal expression * for each pin in the function's pin group evaluates true for the desired @@ -135,19 +148,21 @@ static bool aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, * neither the enabled nor disabled state. Thus we must explicitly test for * either condition as required. */ -static bool aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr, - bool enabled, struct regmap *map) +static int aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr, + bool enabled, struct regmap * const *maps) { int i; + int ret; for (i = 0; i < expr->ndescs; i++) { const struct aspeed_sig_desc *desc = &expr->descs[i]; - if (!aspeed_sig_desc_eval(desc, enabled, map)) - return false; + ret = aspeed_sig_desc_eval(desc, enabled, maps[desc->ip]); + if (ret <= 0) + return ret; } - return true; + return 1; } /** @@ -158,19 +173,24 @@ static bool aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr, * configured * @enable: true to enable an function's signal through a pin's signal * expression, false to disable the function's signal - * @map: The SCU's regmap instance for pinmux register access. + * @maps: The list of regmap instances for pinmux register access. * - * @return true if the expression is configured as requested, false otherwise + * @return 0 if the expression is configured as requested and a negative error + * code otherwise */ -static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr, - bool enable, struct regmap *map) +static int aspeed_sig_expr_set(const struct aspeed_sig_expr *expr, + bool enable, struct regmap * const *maps) { + int ret; int i; for (i = 0; i < expr->ndescs; i++) { - bool ret; const struct aspeed_sig_desc *desc = &expr->descs[i]; u32 pattern = enable ? desc->enable : desc->disable; + u32 val = (pattern << __ffs(desc->mask)); + + if (!maps[desc->ip]) + return -ENODEV; /* * Strap registers are configured in hardware or by early-boot @@ -179,64 +199,79 @@ static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr, * deconfigured and is the reason we re-evaluate after writing * all descriptor bits. */ - if (desc->reg == HW_STRAP1 || desc->reg == HW_STRAP2) + if ((desc->reg == HW_STRAP1 || desc->reg == HW_STRAP2) && + desc->ip == ASPEED_IP_SCU) continue; - ret = regmap_update_bits(map, desc->reg, desc->mask, - pattern << __ffs(desc->mask)) == 0; + ret = regmap_update_bits(maps[desc->ip], desc->reg, + desc->mask, val); - if (!ret) + if (ret) return ret; } - return aspeed_sig_expr_eval(expr, enable, map); + ret = aspeed_sig_expr_eval(expr, enable, maps); + if (ret < 0) + return ret; + + if (!ret) + return -EPERM; + + return 0; } -static bool aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr, - struct regmap *map) +static int aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr, + struct regmap * const *maps) { - if (aspeed_sig_expr_eval(expr, true, map)) - return true; + int ret; - return aspeed_sig_expr_set(expr, true, map); + ret = aspeed_sig_expr_eval(expr, true, maps); + if (ret < 0) + return ret; + + if (!ret) + return aspeed_sig_expr_set(expr, true, maps); + + return 0; } -static bool aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr, - struct regmap *map) +static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr, + struct regmap * const *maps) { - if (!aspeed_sig_expr_eval(expr, true, map)) - return true; + int ret; - return aspeed_sig_expr_set(expr, false, map); + ret = aspeed_sig_expr_eval(expr, true, maps); + if (ret < 0) + return ret; + + if (ret) + return aspeed_sig_expr_set(expr, false, maps); + + return 0; } /** * Disable a signal on a pin by disabling all provided signal expressions. * * @exprs: The list of signal expressions (from a priority level on a pin) - * @map: The SCU's regmap instance for pinmux register access. + * @maps: The list of regmap instances for pinmux register access. * - * @return true if all expressions in the list are successfully disabled, false - * otherwise + * @return 0 if all expressions are disabled, otherwise a negative error code */ -static bool aspeed_disable_sig(const struct aspeed_sig_expr **exprs, - struct regmap *map) +static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs, + struct regmap * const *maps) { - bool disabled = true; + int ret = 0; if (!exprs) return true; - while (*exprs) { - bool ret; - - ret = aspeed_sig_expr_disable(*exprs, map); - disabled = disabled && ret; - + while (*exprs && !ret) { + ret = aspeed_sig_expr_disable(*exprs, maps); exprs++; } - return disabled; + return ret; } /** @@ -330,6 +365,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, unsigned int group) { int i; + int ret; const struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); const struct aspeed_pin_group *pgroup = &pdata->groups[group]; @@ -343,6 +379,8 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, const struct aspeed_sig_expr **funcs; const struct aspeed_sig_expr ***prios; + pr_debug("Muxing pin %d for %s\n", pin, pfunc->name); + if (!pdesc) return -EINVAL; @@ -358,8 +396,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, if (expr) break; - if (!aspeed_disable_sig(funcs, pdata->map)) - return -EPERM; + ret = aspeed_disable_sig(funcs, pdata->maps); + if (ret) + return ret; prios++; } @@ -377,8 +416,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, return -ENXIO; } - if (!aspeed_sig_expr_enable(expr, pdata->map)) - return -EPERM; + ret = aspeed_sig_expr_enable(expr, pdata->maps); + if (ret) + return ret; } return 0; @@ -414,6 +454,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int offset) { + int ret; const struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data; @@ -432,8 +473,9 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, if (aspeed_gpio_in_exprs(funcs)) break; - if (!aspeed_disable_sig(funcs, pdata->map)) - return -EPERM; + ret = aspeed_disable_sig(funcs, pdata->maps); + if (ret) + return ret; prios++; } @@ -462,10 +504,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, * If GPIO is not the lowest priority signal type, assume there is only * one expression defined to enable the GPIO function */ - if (!aspeed_sig_expr_enable(expr, pdata->map)) - return -EPERM; - - return 0; + return aspeed_sig_expr_enable(expr, pdata->maps); } int aspeed_pinctrl_probe(struct platform_device *pdev, @@ -481,10 +520,10 @@ int aspeed_pinctrl_probe(struct platform_device *pdev, return -ENODEV; } - pdata->map = syscon_node_to_regmap(parent->of_node); - if (IS_ERR(pdata->map)) { + pdata->maps[ASPEED_IP_SCU] = syscon_node_to_regmap(parent->of_node); + if (IS_ERR(pdata->maps[ASPEED_IP_SCU])) { dev_err(&pdev->dev, "No regmap for syscon pincontroller parent\n"); - return PTR_ERR(pdata->map); + return PTR_ERR(pdata->maps[ASPEED_IP_SCU]); } pctl = pinctrl_register(pdesc, &pdev->dev, pdata); diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h index 3e72ef8c54bf..0e93cbf2ff33 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h @@ -232,6 +232,11 @@ * group. */ +#define ASPEED_IP_SCU 0 +#define ASPEED_IP_GFX 1 +#define ASPEED_IP_LPC 2 +#define ASPEED_NR_PINMUX_IPS 3 + /* * The "Multi-function Pins Mapping and Control" table in the SoC datasheet * references registers by the device/offset mnemonic. The register macros @@ -261,7 +266,9 @@ * A signal descriptor, which describes the register, bits and the * enable/disable values that should be compared or written. * - * @reg: The register offset from base in bytes + * @ip: The IP block identifier, used as an index into the regmap array in + * struct aspeed_pinctrl_data + * @reg: The register offset with respect to the base address of the IP block * @mask: The mask to apply to the register. The lowest set bit of the mask is * used to derive the shift value. * @enable: The value that enables the function. Value should be in the LSBs, @@ -270,6 +277,7 @@ * LSBs, not at the position of the mask. */ struct aspeed_sig_desc { + unsigned int ip; unsigned int reg; u32 mask; u32 enable; @@ -313,24 +321,30 @@ struct aspeed_pin_desc { /* Macro hell */ +#define SIG_DESC_IP_BIT(ip, reg, idx, val) \ + { ip, reg, BIT_MASK(idx), val, (((val) + 1) & 1) } + /** - * Short-hand macro for describing a configuration enabled by the state of one - * bit. The disable value is derived. + * Short-hand macro for describing an SCU descriptor enabled by the state of + * one bit. The disable value is derived. * * @reg: The signal's associated register, offset from base * @idx: The signal's bit index in the register * @val: The value (0 or 1) that enables the function */ #define SIG_DESC_BIT(reg, idx, val) \ - { reg, BIT_MASK(idx), val, (((val) + 1) & 1) } + SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, val) + +#define SIG_DESC_IP_SET(ip, reg, idx) SIG_DESC_IP_BIT(ip, reg, idx, 1) /** - * A further short-hand macro describing a configuration enabled with a set bit. + * A further short-hand macro expanding to an SCU descriptor enabled by a set + * bit. * - * @reg: The configuration's associated register, offset from base - * @idx: The configuration's bit index in the register + * @reg: The register, offset from base + * @idx: The bit index in the register */ -#define SIG_DESC_SET(reg, idx) SIG_DESC_BIT(reg, idx, 1) +#define SIG_DESC_SET(reg, idx) SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, 1) #define SIG_DESC_LIST_SYM(sig, func) sig_descs_ ## sig ## _ ## func #define SIG_DESC_LIST_DECL(sig, func, ...) \ @@ -500,7 +514,7 @@ struct aspeed_pin_desc { MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(gpio)) struct aspeed_pinctrl_data { - struct regmap *map; + struct regmap *maps[ASPEED_NR_PINMUX_IPS]; const struct pinctrl_pin_desc *pins; const unsigned int npins; From 6d329f14a75f3858a1254abca8b94d4fab556a9a Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Tue, 20 Dec 2016 18:05:49 +1030 Subject: [PATCH 0026/1587] pinctrl: aspeed-g4: Add mux configuration for all pins The patch introducing the g4 pinctrl driver implemented a smattering of pins to flesh out the implementation of the core and provide bare-bones support for some OpenPOWER platforms. Now, update the bindings document to reflect the complete functionality and implement the necessary pin configuration tables in the driver. Cc: Timothy Pearson Signed-off-by: Andrew Jeffery Acked-by: Joel Stanley Acked-by: Rob Herring Signed-off-by: Linus Walleij --- .../bindings/pinctrl/pinctrl-aspeed.txt | 19 +- drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 1097 ++++++++++++++++- 2 files changed, 1096 insertions(+), 20 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt index fb7694ec033d..a645d0be3347 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt @@ -44,13 +44,18 @@ supported: aspeed,ast2400-pinctrl, aspeed,g4-pinctrl: -ACPI BMCINT DDCCLK DDCDAT FLACK FLBUSY FLWP GPID0 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 -I2C11 I2C12 I2C13 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8 I2C9 LPCPD LPCPME LPCSMI MDIO1 -MDIO2 NCTS1 NCTS3 NCTS4 NDCD1 NDCD3 NDCD4 NDSR1 NDSR3 NDTR1 NDTR3 NRI1 NRI3 -NRI4 NRTS1 NRTS3 PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 RGMII1 RMII1 ROM16 -ROM8 ROMCS1 ROMCS2 ROMCS3 ROMCS4 RXD1 RXD3 RXD4 SD1 SGPMI SIOPBI SIOPBO TIMER3 -TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD3 TXD4 UART6 VGAHS VGAVS VPI18 VPI24 VPI30 -VPO12 VPO24 +ACPI ADC0 ADC1 ADC10 ADC11 ADC12 ADC13 ADC14 ADC15 ADC2 ADC3 ADC4 ADC5 ADC6 +ADC7 ADC8 ADC9 BMCINT DDCCLK DDCDAT EXTRST FLACK FLBUSY FLWP GPID GPID0 GPID2 +GPID4 GPID6 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 +I2C5 I2C6 I2C7 I2C8 I2C9 LPCPD LPCPME LPCRST LPCSMI MAC1LINK MAC2LINK MDIO1 +MDIO2 NCTS1 NCTS2 NCTS3 NCTS4 NDCD1 NDCD2 NDCD3 NDCD4 NDSR1 NDSR2 NDSR3 NDSR4 +NDTR1 NDTR2 NDTR3 NDTR4 NDTS4 NRI1 NRI2 NRI3 NRI4 NRTS1 NRTS2 NRTS3 OSCCLK PWM0 +PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 ROM16 ROM8 ROMCS1 +ROMCS2 ROMCS3 ROMCS4 RXD1 RXD2 RXD3 RXD4 SALT1 SALT2 SALT3 SALT4 SD1 SD2 SGPMCK +SGPMI SGPMLD SGPMO SGPSCK SGPSI0 SGPSI1 SGPSLD SIOONCTRL SIOPBI SIOPBO SIOPWREQ +SIOPWRGD SIOS3 SIOS5 SIOSCI SPI1 SPI1DEBUG SPI1PASSTHRU SPICS1 TIMER3 TIMER4 +TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD2 TXD3 TXD4 UART6 USBCKI VGABIOS_ROM VGAHS +VGAVS VPI18 VPI24 VPI30 VPO12 VPO24 WDTRST1 WDTRST2 aspeed,ast2500-pinctrl, aspeed,g5-pinctrl: diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c index 558bd102416c..09b668415c56 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c @@ -43,9 +43,18 @@ * Not all pins have their signals defined (yet). */ +#define D6 0 +SSSF_PIN_DECL(D6, GPIOA0, MAC1LINK, SIG_DESC_SET(SCU80, 0)); + +#define B5 1 +SSSF_PIN_DECL(B5, GPIOA1, MAC2LINK, SIG_DESC_SET(SCU80, 1)); + #define A4 2 SSSF_PIN_DECL(A4, GPIOA2, TIMER3, SIG_DESC_SET(SCU80, 2)); +#define E6 3 +SSSF_PIN_DECL(E6, GPIOA3, TIMER4, SIG_DESC_SET(SCU80, 3)); + #define I2C9_DESC SIG_DESC_SET(SCU90, 22) #define C5 4 @@ -80,6 +89,26 @@ MS_PIN_DECL(D5, GPIOA7, MDIO2, TIMER8); FUNC_GROUP_DECL(TIMER8, D5); FUNC_GROUP_DECL(MDIO2, A3, D5); +#define J21 8 +SSSF_PIN_DECL(J21, GPIOB0, SALT1, SIG_DESC_SET(SCU80, 8)); + +#define J20 9 +SSSF_PIN_DECL(J20, GPIOB1, SALT2, SIG_DESC_SET(SCU80, 9)); + +#define H18 10 +SSSF_PIN_DECL(H18, GPIOB2, SALT3, SIG_DESC_SET(SCU80, 10)); + +#define F18 11 +SSSF_PIN_DECL(F18, GPIOB3, SALT4, SIG_DESC_SET(SCU80, 11)); + +#define E19 12 +SIG_EXPR_DECL(LPCRST, LPCRST, SIG_DESC_SET(SCU80, 12)); +SIG_EXPR_DECL(LPCRST, LPCRSTS, SIG_DESC_SET(HW_STRAP1, 14)); +SIG_EXPR_LIST_DECL_DUAL(LPCRST, LPCRST, LPCRSTS); +SS_PIN_DECL(E19, GPIOB4, LPCRST); + +FUNC_GROUP_DECL(LPCRST, E19); + #define H19 13 #define H19_DESC SIG_DESC_SET(SCU80, 13) SIG_EXPR_LIST_DECL_SINGLE(LPCPD, LPCPD, H19_DESC); @@ -92,6 +121,19 @@ FUNC_GROUP_DECL(LPCSMI, H19); #define H20 14 SSSF_PIN_DECL(H20, GPIOB6, LPCPME, SIG_DESC_SET(SCU80, 14)); +#define E18 15 +SIG_EXPR_LIST_DECL_SINGLE(EXTRST, EXTRST, + SIG_DESC_SET(SCU80, 15), + SIG_DESC_BIT(SCU90, 31, 0), + SIG_DESC_SET(SCU3C, 3)); +SIG_EXPR_LIST_DECL_SINGLE(SPICS1, SPICS1, + SIG_DESC_SET(SCU80, 15), + SIG_DESC_SET(SCU90, 31)); +MS_PIN_DECL(E18, GPIOB7, EXTRST, SPICS1); + +FUNC_GROUP_DECL(EXTRST, E18); +FUNC_GROUP_DECL(SPICS1, E18); + #define SD1_DESC SIG_DESC_SET(SCU90, 0) #define I2C10_DESC SIG_DESC_SET(SCU90, 23) @@ -170,6 +212,62 @@ MS_PIN_DECL(D16, GPIOD1, SD2CMD, GPID0OUT); FUNC_GROUP_DECL(GPID0, A18, D16); +#define GPID2_DESC SIG_DESC_SET(SCU8C, 9) + +#define B17 26 +SIG_EXPR_LIST_DECL_SINGLE(SD2DAT0, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID2IN, GPID2, GPID2_DESC); +SIG_EXPR_DECL(GPID2IN, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID2IN, GPID2, GPID); +MS_PIN_DECL(B17, GPIOD2, SD2DAT0, GPID2IN); + +#define A17 27 +SIG_EXPR_LIST_DECL_SINGLE(SD2DAT1, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID2OUT, GPID2, GPID2_DESC); +SIG_EXPR_DECL(GPID2OUT, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID2OUT, GPID2, GPID); +MS_PIN_DECL(A17, GPIOD3, SD2DAT1, GPID2OUT); + +FUNC_GROUP_DECL(GPID2, B17, A17); + +#define GPID4_DESC SIG_DESC_SET(SCU8C, 10) + +#define C16 28 +SIG_EXPR_LIST_DECL_SINGLE(SD2DAT2, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID4IN, GPID4, GPID4_DESC); +SIG_EXPR_DECL(GPID4IN, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID4IN, GPID4, GPID); +MS_PIN_DECL(C16, GPIOD4, SD2DAT2, GPID4IN); + +#define B16 29 +SIG_EXPR_LIST_DECL_SINGLE(SD2DAT3, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID4OUT, GPID4, GPID4_DESC); +SIG_EXPR_DECL(GPID4OUT, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID4OUT, GPID4, GPID); +MS_PIN_DECL(B16, GPIOD5, SD2DAT3, GPID4OUT); + +FUNC_GROUP_DECL(GPID4, C16, B16); + +#define GPID6_DESC SIG_DESC_SET(SCU8C, 11) + +#define A16 30 +SIG_EXPR_LIST_DECL_SINGLE(SD2CD, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID6IN, GPID6, GPID6_DESC); +SIG_EXPR_DECL(GPID6IN, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID6IN, GPID6, GPID); +MS_PIN_DECL(A16, GPIOD6, SD2CD, GPID6IN); + +#define E15 31 +SIG_EXPR_LIST_DECL_SINGLE(SD2WP, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID6OUT, GPID6, GPID6_DESC); +SIG_EXPR_DECL(GPID6OUT, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID6OUT, GPID6, GPID); +MS_PIN_DECL(E15, GPIOD7, SD2WP, GPID6OUT); + +FUNC_GROUP_DECL(GPID6, A16, E15); +FUNC_GROUP_DECL(SD2, A18, D16, B17, A17, C16, B16, A16, E15); +FUNC_GROUP_DECL(GPID, A18, D16, B17, A17, C16, B16, A16, E15); + #define GPIE_DESC SIG_DESC_SET(HW_STRAP1, 22) #define GPIE0_DESC SIG_DESC_SET(SCU8C, 12) #define GPIE2_DESC SIG_DESC_SET(SCU8C, 13) @@ -266,6 +364,15 @@ MS_PIN_DECL(B19, GPIOF1, NDCD4, SIOPBI); FUNC_GROUP_DECL(NDCD4, B19); FUNC_GROUP_DECL(SIOPBI, B19); +#define A20 42 +SIG_EXPR_LIST_DECL_SINGLE(NDSR4, NDSR4, SIG_DESC_SET(SCU80, 26)); +SIG_EXPR_DECL(SIOPWRGD, SIOPWRGD, SIG_DESC_SET(SCUA4, 12)); +SIG_EXPR_DECL(SIOPWRGD, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOPWRGD, SIOPWRGD, ACPI); +MS_PIN_DECL(A20, GPIOF2, NDSR4, SIOPWRGD); +FUNC_GROUP_DECL(NDSR4, A20); +FUNC_GROUP_DECL(SIOPWRGD, A20); + #define D17 43 SIG_EXPR_LIST_DECL_SINGLE(NRI4, NRI4, SIG_DESC_SET(SCU80, 27)); SIG_EXPR_DECL(SIOPBO, SIOPBO, SIG_DESC_SET(SCUA4, 14)); @@ -275,7 +382,17 @@ MS_PIN_DECL(D17, GPIOF3, NRI4, SIOPBO); FUNC_GROUP_DECL(NRI4, D17); FUNC_GROUP_DECL(SIOPBO, D17); -FUNC_GROUP_DECL(ACPI, B19, D17); +#define B18 44 +SSSF_PIN_DECL(B18, GPIOF4, NDTR4, SIG_DESC_SET(SCU80, 28)); + +#define A19 45 +SIG_EXPR_LIST_DECL_SINGLE(NDTS4, NDTS4, SIG_DESC_SET(SCU80, 29)); +SIG_EXPR_DECL(SIOSCI, SIOSCI, SIG_DESC_SET(SCUA4, 15)); +SIG_EXPR_DECL(SIOSCI, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOSCI, SIOSCI, ACPI); +MS_PIN_DECL(A19, GPIOF5, NDTS4, SIOSCI); +FUNC_GROUP_DECL(NDTS4, A19); +FUNC_GROUP_DECL(SIOSCI, A19); #define E16 46 SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30)); @@ -283,6 +400,34 @@ SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30)); #define C17 47 SSSF_PIN_DECL(C17, GPIOF7, RXD4, SIG_DESC_SET(SCU80, 31)); +#define A14 48 +SSSF_PIN_DECL(A14, GPIOG0, SGPSCK, SIG_DESC_SET(SCU84, 0)); + +#define E13 49 +SSSF_PIN_DECL(E13, GPIOG1, SGPSLD, SIG_DESC_SET(SCU84, 1)); + +#define D13 50 +SSSF_PIN_DECL(D13, GPIOG2, SGPSI0, SIG_DESC_SET(SCU84, 2)); + +#define C13 51 +SSSF_PIN_DECL(C13, GPIOG3, SGPSI1, SIG_DESC_SET(SCU84, 3)); + +#define B13 52 +SIG_EXPR_LIST_DECL_SINGLE(OSCCLK, OSCCLK, SIG_DESC_SET(SCU2C, 1)); +SIG_EXPR_LIST_DECL_SINGLE(WDTRST1, WDTRST1, SIG_DESC_SET(SCU84, 4)); +MS_PIN_DECL(B13, GPIOG4, OSCCLK, WDTRST1); + +FUNC_GROUP_DECL(OSCCLK, B13); +FUNC_GROUP_DECL(WDTRST1, B13); + +#define Y21 53 +SIG_EXPR_LIST_DECL_SINGLE(USBCKI, USBCKI, SIG_DESC_SET(HW_STRAP1, 23)); +SIG_EXPR_LIST_DECL_SINGLE(WDTRST2, WDTRST2, SIG_DESC_SET(SCU84, 5)); +MS_PIN_DECL(Y21, GPIOG5, USBCKI, WDTRST2); + +FUNC_GROUP_DECL(USBCKI, Y21); +FUNC_GROUP_DECL(WDTRST2, Y21); + #define AA22 54 SSSF_PIN_DECL(AA22, GPIOG6, FLBUSY, SIG_DESC_SET(SCU84, 6)); @@ -352,6 +497,93 @@ MS_PIN_DECL(E7, GPIOH7, ROMD15, RXD6); FUNC_GROUP_DECL(UART6, A8, C7, B7, A7, D7, B6, A6, E7); +#define SPI1_DESC \ + { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 1, 0 } +#define SPI1DEBUG_DESC \ + { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 2, 0 } +#define SPI1PASSTHRU_DESC \ + { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 3, 0 } + +#define C22 64 +SIG_EXPR_DECL(SYSCS, SPI1DEBUG, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SYSCS, SPI1PASSTHRU, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL_DUAL(SYSCS, SPI1DEBUG, SPI1PASSTHRU); +SS_PIN_DECL(C22, GPIOI0, SYSCS); + +#define G18 65 +SIG_EXPR_DECL(SYSCK, SPI1DEBUG, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SYSCK, SPI1PASSTHRU, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL_DUAL(SYSCK, SPI1DEBUG, SPI1PASSTHRU); +SS_PIN_DECL(G18, GPIOI1, SYSCK); + +#define D19 66 +SIG_EXPR_DECL(SYSDO, SPI1DEBUG, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SYSDO, SPI1PASSTHRU, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL_DUAL(SYSDO, SPI1DEBUG, SPI1PASSTHRU); +SS_PIN_DECL(D19, GPIOI2, SYSDO); + +#define C20 67 +SIG_EXPR_DECL(SYSDI, SPI1DEBUG, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SYSDI, SPI1PASSTHRU, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL_DUAL(SYSDI, SPI1DEBUG, SPI1PASSTHRU); +SS_PIN_DECL(C20, GPIOI3, SYSDI); + +#define VB_DESC SIG_DESC_SET(HW_STRAP1, 5) + +#define B22 68 +SIG_EXPR_DECL(SPI1CS0, SPI1, SPI1_DESC); +SIG_EXPR_DECL(SPI1CS0, SPI1DEBUG, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SPI1CS0, SPI1PASSTHRU, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL(SPI1CS0, SIG_EXPR_PTR(SPI1CS0, SPI1), + SIG_EXPR_PTR(SPI1CS0, SPI1DEBUG), + SIG_EXPR_PTR(SPI1CS0, SPI1PASSTHRU)); +SIG_EXPR_LIST_DECL_SINGLE(VBCS, VGABIOS_ROM, VB_DESC); +MS_PIN_DECL(B22, GPIOI4, SPI1CS0, VBCS); + +#define G19 69 +SIG_EXPR_DECL(SPI1CK, SPI1, SPI1_DESC); +SIG_EXPR_DECL(SPI1CK, SPI1DEBUG, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SPI1CK, SPI1PASSTHRU, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL(SPI1CK, SIG_EXPR_PTR(SPI1CK, SPI1), + SIG_EXPR_PTR(SPI1CK, SPI1DEBUG), + SIG_EXPR_PTR(SPI1CK, SPI1PASSTHRU)); +SIG_EXPR_LIST_DECL_SINGLE(VBCK, VGABIOS_ROM, VB_DESC); +MS_PIN_DECL(G19, GPIOI5, SPI1CK, VBCK); + +#define C18 70 +SIG_EXPR_DECL(SPI1DO, SPI1, SPI1_DESC); +SIG_EXPR_DECL(SPI1DO, SPI1DEBUG, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SPI1DO, SPI1PASSTHRU, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL(SPI1DO, SIG_EXPR_PTR(SPI1DO, SPI1), + SIG_EXPR_PTR(SPI1DO, SPI1DEBUG), + SIG_EXPR_PTR(SPI1DO, SPI1PASSTHRU)); +SIG_EXPR_LIST_DECL_SINGLE(VBDO, VGABIOS_ROM, VB_DESC); +MS_PIN_DECL(C18, GPIOI6, SPI1DO, VBDO); + +#define E20 71 +SIG_EXPR_DECL(SPI1DI, SPI1, SPI1_DESC); +SIG_EXPR_DECL(SPI1DI, SPI1DEBUG, SPI1DEBUG_DESC); +SIG_EXPR_DECL(SPI1DI, SPI1PASSTHRU, SPI1PASSTHRU_DESC); +SIG_EXPR_LIST_DECL(SPI1DI, SIG_EXPR_PTR(SPI1DI, SPI1), + SIG_EXPR_PTR(SPI1DI, SPI1DEBUG), + SIG_EXPR_PTR(SPI1DI, SPI1PASSTHRU)); +SIG_EXPR_LIST_DECL_SINGLE(VBDI, VGABIOS_ROM, VB_DESC); +MS_PIN_DECL(E20, GPIOI7, SPI1DI, VBDI); + +FUNC_GROUP_DECL(SPI1, B22, G19, C18, E20); +FUNC_GROUP_DECL(SPI1DEBUG, C22, G18, D19, C20, B22, G19, C18, E20); +FUNC_GROUP_DECL(SPI1PASSTHRU, C22, G18, D19, C20, B22, G19, C18, E20); +FUNC_GROUP_DECL(VGABIOS_ROM, B22, G19, C18, E20); + +#define J5 72 +SSSF_PIN_DECL(J5, GPIOJ0, SGPMCK, SIG_DESC_SET(SCU84, 8)); + +#define J4 73 +SSSF_PIN_DECL(J4, GPIOJ1, SGPMLD, SIG_DESC_SET(SCU84, 9)); + +#define K5 74 +SSSF_PIN_DECL(K5, GPIOJ2, SGPMO, SIG_DESC_SET(SCU84, 10)); + #define J3 75 SSSF_PIN_DECL(J3, GPIOJ3, SGPMI, SIG_DESC_SET(SCU84, 11)); @@ -496,6 +728,102 @@ SIG_EXPR_LIST_DECL_SINGLE(RXD1, RXD1, U5_DESC); MS_PIN_DECL(U5, GPIOL7, VPIB1, RXD1); FUNC_GROUP_DECL(RXD1, U5); +#define V3 96 +#define V3_DESC SIG_DESC_SET(SCU84, 24) +SIG_EXPR_DECL(VPIOB2, VPI18, VPI18_DESC, V3_DESC); +SIG_EXPR_DECL(VPIOB2, VPI24, VPI24_DESC, V3_DESC); +SIG_EXPR_DECL(VPIOB2, VPI30, VPI30_DESC, V3_DESC); +SIG_EXPR_LIST_DECL(VPIOB2, SIG_EXPR_PTR(VPIOB2, VPI18), + SIG_EXPR_PTR(VPIOB2, VPI24), + SIG_EXPR_PTR(VPIOB2, VPI30)); +SIG_EXPR_LIST_DECL_SINGLE(NCTS2, NCTS2, V3_DESC); +MS_PIN_DECL(V3, GPIOM0, VPIOB2, NCTS2); +FUNC_GROUP_DECL(NCTS2, V3); + +#define W2 97 +#define W2_DESC SIG_DESC_SET(SCU84, 25) +SIG_EXPR_DECL(VPIOB3, VPI18, VPI18_DESC, W2_DESC); +SIG_EXPR_DECL(VPIOB3, VPI24, VPI24_DESC, W2_DESC); +SIG_EXPR_DECL(VPIOB3, VPI30, VPI30_DESC, W2_DESC); +SIG_EXPR_LIST_DECL(VPIOB3, SIG_EXPR_PTR(VPIOB3, VPI18), + SIG_EXPR_PTR(VPIOB3, VPI24), + SIG_EXPR_PTR(VPIOB3, VPI30)); +SIG_EXPR_LIST_DECL_SINGLE(NDCD2, NDCD2, W2_DESC); +MS_PIN_DECL(W2, GPIOM1, VPIOB3, NDCD2); +FUNC_GROUP_DECL(NDCD2, W2); + +#define Y1 98 +#define Y1_DESC SIG_DESC_SET(SCU84, 26) +SIG_EXPR_DECL(VPIOB4, VPI18, VPI18_DESC, Y1_DESC); +SIG_EXPR_DECL(VPIOB4, VPI24, VPI24_DESC, Y1_DESC); +SIG_EXPR_DECL(VPIOB4, VPI30, VPI30_DESC, Y1_DESC); +SIG_EXPR_LIST_DECL(VPIOB4, SIG_EXPR_PTR(VPIOB4, VPI18), + SIG_EXPR_PTR(VPIOB4, VPI24), + SIG_EXPR_PTR(VPIOB4, VPI30)); +SIG_EXPR_LIST_DECL_SINGLE(NDSR2, NDSR2, Y1_DESC); +MS_PIN_DECL(Y1, GPIOM2, VPIOB4, NDSR2); +FUNC_GROUP_DECL(NDSR2, Y1); + +#define V4 99 +#define V4_DESC SIG_DESC_SET(SCU84, 27) +SIG_EXPR_DECL(VPIOB5, VPI18, VPI18_DESC, V4_DESC); +SIG_EXPR_DECL(VPIOB5, VPI24, VPI24_DESC, V4_DESC); +SIG_EXPR_DECL(VPIOB5, VPI30, VPI30_DESC, V4_DESC); +SIG_EXPR_LIST_DECL(VPIOB5, SIG_EXPR_PTR(VPIOB5, VPI18), + SIG_EXPR_PTR(VPIOB5, VPI24), + SIG_EXPR_PTR(VPIOB5, VPI30)); +SIG_EXPR_LIST_DECL_SINGLE(NRI2, NRI2, V4_DESC); +MS_PIN_DECL(V4, GPIOM3, VPIOB5, NRI2); +FUNC_GROUP_DECL(NRI2, V4); + +#define W3 100 +#define W3_DESC SIG_DESC_SET(SCU84, 28) +SIG_EXPR_DECL(VPIOB6, VPI18, VPI18_DESC, W3_DESC); +SIG_EXPR_DECL(VPIOB6, VPI24, VPI24_DESC, W3_DESC); +SIG_EXPR_DECL(VPIOB6, VPI30, VPI30_DESC, W3_DESC); +SIG_EXPR_LIST_DECL(VPIOB6, SIG_EXPR_PTR(VPIOB6, VPI18), + SIG_EXPR_PTR(VPIOB6, VPI24), + SIG_EXPR_PTR(VPIOB6, VPI30)); +SIG_EXPR_LIST_DECL_SINGLE(NDTR2, NDTR2, W3_DESC); +MS_PIN_DECL(W3, GPIOM4, VPIOB6, NDTR2); +FUNC_GROUP_DECL(NDTR2, W3); + +#define Y2 101 +#define Y2_DESC SIG_DESC_SET(SCU84, 29) +SIG_EXPR_DECL(VPIOB7, VPI18, VPI18_DESC, Y2_DESC); +SIG_EXPR_DECL(VPIOB7, VPI24, VPI24_DESC, Y2_DESC); +SIG_EXPR_DECL(VPIOB7, VPI30, VPI30_DESC, Y2_DESC); +SIG_EXPR_LIST_DECL(VPIOB7, SIG_EXPR_PTR(VPIOB7, VPI18), + SIG_EXPR_PTR(VPIOB7, VPI24), + SIG_EXPR_PTR(VPIOB7, VPI30)); +SIG_EXPR_LIST_DECL_SINGLE(NRTS2, NRTS2, Y2_DESC); +MS_PIN_DECL(Y2, GPIOM5, VPIOB7, NRTS2); +FUNC_GROUP_DECL(NRTS2, Y2); + +#define AA1 102 +#define AA1_DESC SIG_DESC_SET(SCU84, 30) +SIG_EXPR_DECL(VPIOB8, VPI18, VPI18_DESC, AA1_DESC); +SIG_EXPR_DECL(VPIOB8, VPI24, VPI24_DESC, AA1_DESC); +SIG_EXPR_DECL(VPIOB8, VPI30, VPI30_DESC, AA1_DESC); +SIG_EXPR_LIST_DECL(VPIOB8, SIG_EXPR_PTR(VPIOB8, VPI18), + SIG_EXPR_PTR(VPIOB8, VPI24), + SIG_EXPR_PTR(VPIOB8, VPI30)); +SIG_EXPR_LIST_DECL_SINGLE(TXD2, TXD2, AA1_DESC); +MS_PIN_DECL(AA1, GPIOM6, VPIOB8, TXD2); +FUNC_GROUP_DECL(TXD2, AA1); + +#define V5 103 +#define V5_DESC SIG_DESC_SET(SCU84, 31) +SIG_EXPR_DECL(VPIOB9, VPI18, VPI18_DESC, V5_DESC); +SIG_EXPR_DECL(VPIOB9, VPI24, VPI24_DESC, V5_DESC); +SIG_EXPR_DECL(VPIOB9, VPI30, VPI30_DESC, V5_DESC); +SIG_EXPR_LIST_DECL(VPIOB9, SIG_EXPR_PTR(VPIOB9, VPI18), + SIG_EXPR_PTR(VPIOB9, VPI24), + SIG_EXPR_PTR(VPIOB9, VPI30)); +SIG_EXPR_LIST_DECL_SINGLE(RXD2, RXD2, V5_DESC); +MS_PIN_DECL(V5, GPIOM7, VPIOB9, RXD2); +FUNC_GROUP_DECL(RXD2, V5); + #define W4 104 #define W4_DESC SIG_DESC_SET(SCU88, 0) SIG_EXPR_LIST_DECL_SINGLE(VPIG0, VPI30, VPI30_DESC, W4_DESC); @@ -580,10 +908,57 @@ SS_PIN_DECL(V6, GPIOO0, VPIG8); SIG_EXPR_LIST_DECL_SINGLE(VPIG9, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 9)); SS_PIN_DECL(Y5, GPIOO1, VPIG9); -FUNC_GROUP_DECL(VPI18, T5, U3, V1, U4, V2, AA22, W5, Y4, AA3, AB2); -FUNC_GROUP_DECL(VPI24, T5, U3, V1, U4, V2, AA22, W5, Y4, AA3, AB2, V6, Y5); -FUNC_GROUP_DECL(VPI30, T5, U3, V1, U4, V2, W1, U5, W4, Y3, AA22, W5, Y4, AA3, - AB2); +#define AA4 114 +SIG_EXPR_LIST_DECL_SINGLE(VPIR0, VPI30, VPI30_DESC, SIG_DESC_SET(SCU88, 10)); +SS_PIN_DECL(AA4, GPIOO2, VPIR0); + +#define AB3 115 +SIG_EXPR_LIST_DECL_SINGLE(VPIR1, VPI30, VPI30_DESC, SIG_DESC_SET(SCU88, 11)); +SS_PIN_DECL(AB3, GPIOO3, VPIR1); + +#define W6 116 +SIG_EXPR_LIST_DECL_SINGLE(VPIR2, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 12)); +SS_PIN_DECL(W6, GPIOO4, VPIR2); + +#define AA5 117 +SIG_EXPR_LIST_DECL_SINGLE(VPIR3, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 13)); +SS_PIN_DECL(AA5, GPIOO5, VPIR3); + +#define AB4 118 +SIG_EXPR_LIST_DECL_SINGLE(VPIR4, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 14)); +SS_PIN_DECL(AB4, GPIOO6, VPIR4); + +#define V7 119 +SIG_EXPR_LIST_DECL_SINGLE(VPIR5, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 15)); +SS_PIN_DECL(V7, GPIOO7, VPIR5); + +#define Y6 120 +SIG_EXPR_LIST_DECL_SINGLE(VPIR6, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 16)); +SS_PIN_DECL(Y6, GPIOP0, VPIR6); + +#define AB5 121 +SIG_EXPR_LIST_DECL_SINGLE(VPIR7, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 17)); +SS_PIN_DECL(AB5, GPIOP1, VPIR7); + +#define W7 122 +SIG_EXPR_LIST_DECL_SINGLE(VPIR8, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 18)); +SS_PIN_DECL(W7, GPIOP2, VPIR8); + +#define AA6 123 +SIG_EXPR_LIST_DECL_SINGLE(VPIR9, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 19)); +SS_PIN_DECL(AA6, GPIOP3, VPIR9); + +FUNC_GROUP_DECL(VPI18, T5, U3, V1, U4, V2, V3, W2, Y1, V4, W3, Y2, AA1, V5, + AA22, W5, Y4, AA3, AB2); +FUNC_GROUP_DECL(VPI24, T5, U3, V1, U4, V2, V3, W2, Y1, V4, W3, Y2, AA1, V5, + AA22, W5, Y4, AA3, AB2, V6, Y5, W6, AA5, AB4, V7, Y6, AB5, W7, + AA6); +FUNC_GROUP_DECL(VPI30, T5, U3, V1, U4, V2, W1, U5, V3, W2, Y1, V4, W3, Y2, AA1, + V5, W4, Y3, AA22, W5, Y4, AA3, AB2, AA4, AB3); + +#define AB6 124 +SIG_EXPR_LIST_DECL_SINGLE(GPIOP4, GPIOP4); +MS_PIN_DECL_(AB6, SIG_EXPR_LIST_PTR(GPIOP4)); #define Y7 125 SIG_EXPR_LIST_DECL_SINGLE(GPIOP5, GPIOP5); @@ -619,6 +994,18 @@ SS_PIN_DECL(F5, GPIOQ3, SDA4); FUNC_GROUP_DECL(I2C4, B1, F5); +#define I2C14_DESC SIG_DESC_SET(SCU90, 27) + +#define H4 132 +SIG_EXPR_LIST_DECL_SINGLE(SCL14, I2C14, I2C14_DESC); +SS_PIN_DECL(H4, GPIOQ4, SCL14); + +#define H3 133 +SIG_EXPR_LIST_DECL_SINGLE(SDA14, I2C14, I2C14_DESC); +SS_PIN_DECL(H3, GPIOQ5, SDA14); + +FUNC_GROUP_DECL(I2C14, H4, H3); + #define DASH9028_DESC SIG_DESC_SET(SCU90, 28) #define H2 134 @@ -776,13 +1163,6 @@ SIG_EXPR_LIST_DECL(ROMA23, SIG_EXPR_PTR(ROMA23, ROM8), SIG_EXPR_LIST_DECL_SINGLE(VPOR5, VPO24, K18_DESC, VPO_24_OFF); MS_PIN_DECL(K18, GPIOS7, ROMA23, VPOR5); -FUNC_GROUP_DECL(ROM8, V20, U21, T19, V22, U20, R18, N21, L22, K18, W21, Y22, - U19); -FUNC_GROUP_DECL(ROM16, V20, U21, T19, V22, U20, R18, N21, L22, K18, - A8, C7, B7, A7, D7, B6, A6, E7, W21, Y22, U19); -FUNC_GROUP_DECL(VPO12, U21, T19, V22, U20); -FUNC_GROUP_DECL(VPO24, U21, T19, V22, U20, L22, K18, V21, W22); - #define RMII1_DESC SIG_DESC_BIT(HW_STRAP1, 6, 0) #define A12 152 @@ -827,6 +1207,50 @@ SIG_EXPR_LIST_DECL_SINGLE(RGMII1TXD3, RGMII1); MS_PIN_DECL_(A13, SIG_EXPR_LIST_PTR(GPIOT5), SIG_EXPR_LIST_PTR(DASHA13), SIG_EXPR_LIST_PTR(RGMII1TXD3)); +#define RMII2_DESC SIG_DESC_BIT(HW_STRAP1, 7, 0) + +#define D9 158 +SIG_EXPR_LIST_DECL_SINGLE(GPIOT6, GPIOT6, SIG_DESC_SET(SCUA0, 6)); +SIG_EXPR_LIST_DECL_SINGLE(RMII2TXEN, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXCK, RGMII2); +MS_PIN_DECL_(D9, SIG_EXPR_LIST_PTR(GPIOT6), SIG_EXPR_LIST_PTR(RMII2TXEN), + SIG_EXPR_LIST_PTR(RGMII2TXCK)); + +#define E9 159 +SIG_EXPR_LIST_DECL_SINGLE(GPIOT7, GPIOT7, SIG_DESC_SET(SCUA0, 7)); +SIG_EXPR_LIST_DECL_SINGLE(DASHE9, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXCTL, RGMII2); +MS_PIN_DECL_(E9, SIG_EXPR_LIST_PTR(GPIOT7), SIG_EXPR_LIST_PTR(DASHE9), + SIG_EXPR_LIST_PTR(RGMII2TXCTL)); + +#define A10 160 +SIG_EXPR_LIST_DECL_SINGLE(GPIOU0, GPIOU0, SIG_DESC_SET(SCUA0, 8)); +SIG_EXPR_LIST_DECL_SINGLE(RMII2TXD0, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXD0, RGMII2); +MS_PIN_DECL_(A10, SIG_EXPR_LIST_PTR(GPIOU0), SIG_EXPR_LIST_PTR(RMII2TXD0), + SIG_EXPR_LIST_PTR(RGMII2TXD0)); + +#define B10 161 +SIG_EXPR_LIST_DECL_SINGLE(GPIOU1, GPIOU1, SIG_DESC_SET(SCUA0, 9)); +SIG_EXPR_LIST_DECL_SINGLE(RMII2TXD1, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXD1, RGMII2); +MS_PIN_DECL_(B10, SIG_EXPR_LIST_PTR(GPIOU1), SIG_EXPR_LIST_PTR(RMII2TXD1), + SIG_EXPR_LIST_PTR(RGMII2TXD1)); + +#define C10 162 +SIG_EXPR_LIST_DECL_SINGLE(GPIOU2, GPIOU2, SIG_DESC_SET(SCUA0, 10)); +SIG_EXPR_LIST_DECL_SINGLE(DASHC10, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXD2, RGMII2); +MS_PIN_DECL_(C10, SIG_EXPR_LIST_PTR(GPIOU2), SIG_EXPR_LIST_PTR(DASHC10), + SIG_EXPR_LIST_PTR(RGMII2TXD2)); + +#define D10 163 +SIG_EXPR_LIST_DECL_SINGLE(GPIOU3, GPIOU3, SIG_DESC_SET(SCUA0, 11)); +SIG_EXPR_LIST_DECL_SINGLE(DASHD10, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXD3, RGMII2); +MS_PIN_DECL_(D10, SIG_EXPR_LIST_PTR(GPIOU3), SIG_EXPR_LIST_PTR(DASHD10), + SIG_EXPR_LIST_PTR(RGMII2TXD3)); + #define E11 164 SIG_EXPR_LIST_DECL_SINGLE(GPIOU4, GPIOU4, SIG_DESC_SET(SCUA0, 12)); SIG_EXPR_LIST_DECL_SINGLE(RMII1RCLK, RMII1, RMII1_DESC); @@ -869,11 +1293,419 @@ SIG_EXPR_LIST_DECL_SINGLE(RGMII1RXD3, RGMII1); MS_PIN_DECL_(E10, SIG_EXPR_LIST_PTR(GPIOV1), SIG_EXPR_LIST_PTR(RMII1RXER), SIG_EXPR_LIST_PTR(RGMII1RXD3)); +#define C9 170 +SIG_EXPR_LIST_DECL_SINGLE(GPIOV2, GPIOV2, SIG_DESC_SET(SCUA0, 18)); +SIG_EXPR_LIST_DECL_SINGLE(RMII2RCLK, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXCK, RGMII2); +MS_PIN_DECL_(C9, SIG_EXPR_LIST_PTR(GPIOV2), SIG_EXPR_LIST_PTR(RMII2RCLK), + SIG_EXPR_LIST_PTR(RGMII2RXCK)); + +#define B9 171 +SIG_EXPR_LIST_DECL_SINGLE(GPIOV3, GPIOV3, SIG_DESC_SET(SCUA0, 19)); +SIG_EXPR_LIST_DECL_SINGLE(DASHB9, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXCTL, RGMII2); +MS_PIN_DECL_(B9, SIG_EXPR_LIST_PTR(GPIOV3), SIG_EXPR_LIST_PTR(DASHB9), + SIG_EXPR_LIST_PTR(RGMII2RXCTL)); + +#define A9 172 +SIG_EXPR_LIST_DECL_SINGLE(GPIOV4, GPIOV4, SIG_DESC_SET(SCUA0, 20)); +SIG_EXPR_LIST_DECL_SINGLE(RMII2RXD0, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXD0, RGMII2); +MS_PIN_DECL_(A9, SIG_EXPR_LIST_PTR(GPIOV4), SIG_EXPR_LIST_PTR(RMII2RXD0), + SIG_EXPR_LIST_PTR(RGMII2RXD0)); + +#define E8 173 +SIG_EXPR_LIST_DECL_SINGLE(GPIOV5, GPIOV5, SIG_DESC_SET(SCUA0, 21)); +SIG_EXPR_LIST_DECL_SINGLE(RMII2RXD1, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXD1, RGMII2); +MS_PIN_DECL_(E8, SIG_EXPR_LIST_PTR(GPIOV5), SIG_EXPR_LIST_PTR(RMII2RXD1), + SIG_EXPR_LIST_PTR(RGMII2RXD1)); + +#define D8 174 +SIG_EXPR_LIST_DECL_SINGLE(GPIOV6, GPIOV6, SIG_DESC_SET(SCUA0, 22)); +SIG_EXPR_LIST_DECL_SINGLE(RMII2CRSDV, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXD2, RGMII2); +MS_PIN_DECL_(D8, SIG_EXPR_LIST_PTR(GPIOV6), SIG_EXPR_LIST_PTR(RMII2CRSDV), + SIG_EXPR_LIST_PTR(RGMII2RXD2)); + +#define C8 175 +SIG_EXPR_LIST_DECL_SINGLE(GPIOV7, GPIOV7, SIG_DESC_SET(SCUA0, 23)); +SIG_EXPR_LIST_DECL_SINGLE(RMII2RXER, RMII2, RMII2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXD3, RGMII2); +MS_PIN_DECL_(C8, SIG_EXPR_LIST_PTR(GPIOV7), SIG_EXPR_LIST_PTR(RMII2RXER), + SIG_EXPR_LIST_PTR(RGMII2RXD3)); + FUNC_GROUP_DECL(RMII1, A12, B12, C12, D12, E12, A13, E11, D11, C11, B11, A11, E10); FUNC_GROUP_DECL(RGMII1, A12, B12, C12, D12, E12, A13, E11, D11, C11, B11, A11, E10); +FUNC_GROUP_DECL(RMII2, D9, E9, A10, B10, C10, D10, C9, B9, A9, E8, D8, C8); +FUNC_GROUP_DECL(RGMII2, D9, E9, A10, B10, C10, D10, C9, B9, A9, E8, D8, C8); + +#define L5 176 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW0, GPIOW0, SIG_DESC_SET(SCUA0, 24)); +SIG_EXPR_LIST_DECL_SINGLE(ADC0, ADC0); +MS_PIN_DECL_(L5, SIG_EXPR_LIST_PTR(GPIOW0), SIG_EXPR_LIST_PTR(ADC0)); +FUNC_GROUP_DECL(ADC0, L5); + +#define L4 177 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW1, GPIOW1, SIG_DESC_SET(SCUA0, 25)); +SIG_EXPR_LIST_DECL_SINGLE(ADC1, ADC1); +MS_PIN_DECL_(L4, SIG_EXPR_LIST_PTR(GPIOW1), SIG_EXPR_LIST_PTR(ADC1)); +FUNC_GROUP_DECL(ADC1, L4); + +#define L3 178 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW2, GPIOW2, SIG_DESC_SET(SCUA0, 26)); +SIG_EXPR_LIST_DECL_SINGLE(ADC2, ADC2); +MS_PIN_DECL_(L3, SIG_EXPR_LIST_PTR(GPIOW2), SIG_EXPR_LIST_PTR(ADC2)); +FUNC_GROUP_DECL(ADC2, L3); + +#define L2 179 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW3, GPIOW3, SIG_DESC_SET(SCUA0, 27)); +SIG_EXPR_LIST_DECL_SINGLE(ADC3, ADC3); +MS_PIN_DECL_(L2, SIG_EXPR_LIST_PTR(GPIOW3), SIG_EXPR_LIST_PTR(ADC3)); +FUNC_GROUP_DECL(ADC3, L2); + +#define L1 180 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW4, GPIOW4, SIG_DESC_SET(SCUA0, 28)); +SIG_EXPR_LIST_DECL_SINGLE(ADC4, ADC4); +MS_PIN_DECL_(L1, SIG_EXPR_LIST_PTR(GPIOW4), SIG_EXPR_LIST_PTR(ADC4)); +FUNC_GROUP_DECL(ADC4, L1); + +#define M5 181 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW5, GPIOW5, SIG_DESC_SET(SCUA0, 29)); +SIG_EXPR_LIST_DECL_SINGLE(ADC5, ADC5); +MS_PIN_DECL_(M5, SIG_EXPR_LIST_PTR(GPIOW5), SIG_EXPR_LIST_PTR(ADC5)); +FUNC_GROUP_DECL(ADC5, M5); + +#define M4 182 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW6, GPIOW6, SIG_DESC_SET(SCUA0, 30)); +SIG_EXPR_LIST_DECL_SINGLE(ADC6, ADC6); +MS_PIN_DECL_(M4, SIG_EXPR_LIST_PTR(GPIOW6), SIG_EXPR_LIST_PTR(ADC6)); +FUNC_GROUP_DECL(ADC6, M4); + +#define M3 183 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW7, GPIOW7, SIG_DESC_SET(SCUA0, 31)); +SIG_EXPR_LIST_DECL_SINGLE(ADC7, ADC7); +MS_PIN_DECL_(M3, SIG_EXPR_LIST_PTR(GPIOW7), SIG_EXPR_LIST_PTR(ADC7)); +FUNC_GROUP_DECL(ADC7, M3); + +#define M2 184 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX0, GPIOX0, SIG_DESC_SET(SCUA4, 0)); +SIG_EXPR_LIST_DECL_SINGLE(ADC8, ADC8); +MS_PIN_DECL_(M2, SIG_EXPR_LIST_PTR(GPIOX0), SIG_EXPR_LIST_PTR(ADC8)); +FUNC_GROUP_DECL(ADC8, M2); + +#define M1 185 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX1, GPIOX1, SIG_DESC_SET(SCUA4, 1)); +SIG_EXPR_LIST_DECL_SINGLE(ADC9, ADC9); +MS_PIN_DECL_(M1, SIG_EXPR_LIST_PTR(GPIOX1), SIG_EXPR_LIST_PTR(ADC9)); +FUNC_GROUP_DECL(ADC9, M1); + +#define N5 186 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX2, GPIOX2, SIG_DESC_SET(SCUA4, 2)); +SIG_EXPR_LIST_DECL_SINGLE(ADC10, ADC10); +MS_PIN_DECL_(N5, SIG_EXPR_LIST_PTR(GPIOX2), SIG_EXPR_LIST_PTR(ADC10)); +FUNC_GROUP_DECL(ADC10, N5); + +#define N4 187 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX3, GPIOX3, SIG_DESC_SET(SCUA4, 3)); +SIG_EXPR_LIST_DECL_SINGLE(ADC11, ADC11); +MS_PIN_DECL_(N4, SIG_EXPR_LIST_PTR(GPIOX3), SIG_EXPR_LIST_PTR(ADC11)); +FUNC_GROUP_DECL(ADC11, N4); + +#define N3 188 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX4, GPIOX4, SIG_DESC_SET(SCUA4, 4)); +SIG_EXPR_LIST_DECL_SINGLE(ADC12, ADC12); +MS_PIN_DECL_(N3, SIG_EXPR_LIST_PTR(GPIOX4), SIG_EXPR_LIST_PTR(ADC12)); +FUNC_GROUP_DECL(ADC12, N3); + +#define N2 189 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX5, GPIOX5, SIG_DESC_SET(SCUA4, 5)); +SIG_EXPR_LIST_DECL_SINGLE(ADC13, ADC13); +MS_PIN_DECL_(N2, SIG_EXPR_LIST_PTR(GPIOX5), SIG_EXPR_LIST_PTR(ADC13)); +FUNC_GROUP_DECL(ADC13, N2); + +#define N1 190 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX6, GPIOX6, SIG_DESC_SET(SCUA4, 6)); +SIG_EXPR_LIST_DECL_SINGLE(ADC14, ADC14); +MS_PIN_DECL_(N1, SIG_EXPR_LIST_PTR(GPIOX6), SIG_EXPR_LIST_PTR(ADC14)); +FUNC_GROUP_DECL(ADC14, N1); + +#define P5 191 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX7, GPIOX7, SIG_DESC_SET(SCUA4, 7)); +SIG_EXPR_LIST_DECL_SINGLE(ADC15, ADC15); +MS_PIN_DECL_(P5, SIG_EXPR_LIST_PTR(GPIOX7), SIG_EXPR_LIST_PTR(ADC15)); +FUNC_GROUP_DECL(ADC15, P5); + +#define C21 192 +SIG_EXPR_DECL(SIOS3, SIOS3, SIG_DESC_SET(SCUA4, 8)); +SIG_EXPR_DECL(SIOS3, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOS3, SIOS3, ACPI); +SS_PIN_DECL(C21, GPIOY0, SIOS3); +FUNC_GROUP_DECL(SIOS3, C21); + +#define F20 193 +SIG_EXPR_DECL(SIOS5, SIOS5, SIG_DESC_SET(SCUA4, 9)); +SIG_EXPR_DECL(SIOS5, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOS5, SIOS5, ACPI); +SS_PIN_DECL(F20, GPIOY1, SIOS5); +FUNC_GROUP_DECL(SIOS5, F20); + +#define G20 194 +SIG_EXPR_DECL(SIOPWREQ, SIOPWREQ, SIG_DESC_SET(SCUA4, 10)); +SIG_EXPR_DECL(SIOPWREQ, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOPWREQ, SIOPWREQ, ACPI); +SS_PIN_DECL(G20, GPIOY2, SIOPWREQ); +FUNC_GROUP_DECL(SIOPWREQ, G20); + +#define K20 195 +SIG_EXPR_DECL(SIOONCTRL, SIOONCTRL, SIG_DESC_SET(SCUA4, 11)); +SIG_EXPR_DECL(SIOONCTRL, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOONCTRL, SIOONCTRL, ACPI); +SS_PIN_DECL(K20, GPIOY3, SIOONCTRL); +FUNC_GROUP_DECL(SIOONCTRL, K20); + +FUNC_GROUP_DECL(ACPI, B19, A20, D17, A19, C21, F20, G20, K20); + +#define R22 200 +#define R22_DESC SIG_DESC_SET(SCUA4, 16) +SIG_EXPR_DECL(ROMA2, ROM8, R22_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA2, ROM16, R22_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA2, ROM8, ROM16); +SIG_EXPR_DECL(VPOB0, VPO12, R22_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOB0, VPO24, R22_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOB0, VPOOFF1, R22_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOB0, SIG_EXPR_PTR(VPOB0, VPO12), + SIG_EXPR_PTR(VPOB0, VPO24), SIG_EXPR_PTR(VPOB0, VPOOFF1)); +MS_PIN_DECL(R22, GPIOZ0, ROMA2, VPOB0); + +#define P18 201 +#define P18_DESC SIG_DESC_SET(SCUA4, 17) +SIG_EXPR_DECL(ROMA3, ROM8, P18_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA3, ROM16, P18_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA3, ROM8, ROM16); +SIG_EXPR_DECL(VPOB1, VPO12, P18_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOB1, VPO24, P18_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOB1, VPOOFF1, P18_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOB1, SIG_EXPR_PTR(VPOB1, VPO12), + SIG_EXPR_PTR(VPOB1, VPO24), SIG_EXPR_PTR(VPOB1, VPOOFF1)); +MS_PIN_DECL(P18, GPIOZ1, ROMA3, VPOB1); + +#define P19 202 +#define P19_DESC SIG_DESC_SET(SCUA4, 18) +SIG_EXPR_DECL(ROMA4, ROM8, P19_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA4, ROM16, P19_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA4, ROM8, ROM16); +SIG_EXPR_DECL(VPOB2, VPO12, P19_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOB2, VPO24, P19_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOB2, VPOOFF1, P19_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOB2, SIG_EXPR_PTR(VPOB2, VPO12), + SIG_EXPR_PTR(VPOB2, VPO24), SIG_EXPR_PTR(VPOB2, VPOOFF1)); +MS_PIN_DECL(P19, GPIOZ2, ROMA4, VPOB2); + +#define P20 203 +#define P20_DESC SIG_DESC_SET(SCUA4, 19) +SIG_EXPR_DECL(ROMA5, ROM8, P20_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA5, ROM16, P20_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA5, ROM8, ROM16); +SIG_EXPR_DECL(VPOB3, VPO12, P20_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOB3, VPO24, P20_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOB3, VPOOFF1, P20_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOB3, SIG_EXPR_PTR(VPOB3, VPO12), + SIG_EXPR_PTR(VPOB3, VPO24), SIG_EXPR_PTR(VPOB3, VPOOFF1)); +MS_PIN_DECL(P20, GPIOZ3, ROMA5, VPOB3); + +#define P21 204 +#define P21_DESC SIG_DESC_SET(SCUA4, 20) +SIG_EXPR_DECL(ROMA6, ROM8, P21_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA6, ROM16, P21_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA6, ROM8, ROM16); +SIG_EXPR_DECL(VPOB4, VPO12, P21_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOB4, VPO24, P21_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOB4, VPOOFF1, P21_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOB4, SIG_EXPR_PTR(VPOB4, VPO12), + SIG_EXPR_PTR(VPOB4, VPO24), SIG_EXPR_PTR(VPOB4, VPOOFF1)); +MS_PIN_DECL(P21, GPIOZ4, ROMA6, VPOB4); + +#define P22 205 +#define P22_DESC SIG_DESC_SET(SCUA4, 21) +SIG_EXPR_DECL(ROMA7, ROM8, P22_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA7, ROM16, P22_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA7, ROM8, ROM16); +SIG_EXPR_DECL(VPOB5, VPO12, P22_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOB5, VPO24, P22_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOB5, VPOOFF1, P22_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOB5, SIG_EXPR_PTR(VPOB5, VPO12), + SIG_EXPR_PTR(VPOB5, VPO24), SIG_EXPR_PTR(VPOB5, VPOOFF1)); +MS_PIN_DECL(P22, GPIOZ5, ROMA7, VPOB5); + +#define M19 206 +#define M19_DESC SIG_DESC_SET(SCUA4, 22) +SIG_EXPR_DECL(ROMA8, ROM8, M19_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA8, ROM16, M19_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA8, ROM8, ROM16); +SIG_EXPR_DECL(VPOB6, VPO12, M19_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOB6, VPO24, M19_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOB6, VPOOFF1, M19_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOB6, SIG_EXPR_PTR(VPOB6, VPO12), + SIG_EXPR_PTR(VPOB6, VPO24), SIG_EXPR_PTR(VPOB6, VPOOFF1)); +MS_PIN_DECL(M19, GPIOZ6, ROMA8, VPOB6); + +#define M20 207 +#define M20_DESC SIG_DESC_SET(SCUA4, 23) +SIG_EXPR_DECL(ROMA9, ROM8, M20_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA9, ROM16, M20_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA9, ROM8, ROM16); +SIG_EXPR_DECL(VPOB7, VPO12, M20_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOB7, VPO24, M20_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOB7, VPOOFF1, M20_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOB7, SIG_EXPR_PTR(VPOB7, VPO12), + SIG_EXPR_PTR(VPOB7, VPO24), SIG_EXPR_PTR(VPOB7, VPOOFF1)); +MS_PIN_DECL(M20, GPIOZ7, ROMA9, VPOB7); + +#define M21 208 +#define M21_DESC SIG_DESC_SET(SCUA4, 24) +SIG_EXPR_DECL(ROMA10, ROM8, M21_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA10, ROM16, M21_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA10, ROM8, ROM16); +SIG_EXPR_DECL(VPOG0, VPO12, M21_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOG0, VPO24, M21_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOG0, VPOOFF1, M21_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOG0, SIG_EXPR_PTR(VPOG0, VPO12), + SIG_EXPR_PTR(VPOG0, VPO24), SIG_EXPR_PTR(VPOG0, VPOOFF1)); +MS_PIN_DECL(M21, GPIOAA0, ROMA10, VPOG0); + +#define M22 209 +#define M22_DESC SIG_DESC_SET(SCUA4, 25) +SIG_EXPR_DECL(ROMA11, ROM8, M22_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA11, ROM16, M22_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA11, ROM8, ROM16); +SIG_EXPR_DECL(VPOG1, VPO12, M22_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOG1, VPO24, M22_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOG1, VPOOFF1, M22_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOG1, SIG_EXPR_PTR(VPOG1, VPO12), + SIG_EXPR_PTR(VPOG1, VPO24), SIG_EXPR_PTR(VPOG1, VPOOFF1)); +MS_PIN_DECL(M22, GPIOAA1, ROMA11, VPOG1); + +#define L18 210 +#define L18_DESC SIG_DESC_SET(SCUA4, 26) +SIG_EXPR_DECL(ROMA12, ROM8, L18_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA12, ROM16, L18_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA12, ROM8, ROM16); +SIG_EXPR_DECL(VPOG2, VPO12, L18_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOG2, VPO24, L18_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOG2, VPOOFF1, L18_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOG2, SIG_EXPR_PTR(VPOG2, VPO12), + SIG_EXPR_PTR(VPOG2, VPO24), SIG_EXPR_PTR(VPOG2, VPOOFF1)); +MS_PIN_DECL(L18, GPIOAA2, ROMA12, VPOG2); + +#define L19 211 +#define L19_DESC SIG_DESC_SET(SCUA4, 27) +SIG_EXPR_DECL(ROMA13, ROM8, L19_DESC, VPOOFF0_DESC); +SIG_EXPR_DECL(ROMA13, ROM16, L19_DESC, VPOOFF0_DESC); +SIG_EXPR_LIST_DECL_DUAL(ROMA13, ROM8, ROM16); +SIG_EXPR_DECL(VPOG3, VPO12, L19_DESC, VPO12_DESC); +SIG_EXPR_DECL(VPOG3, VPO24, L19_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOG3, VPOOFF1, L19_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL(VPOG3, SIG_EXPR_PTR(VPOG3, VPO12), + SIG_EXPR_PTR(VPOG3, VPO24), SIG_EXPR_PTR(VPOG3, VPOOFF1)); +MS_PIN_DECL(L19, GPIOAA3, ROMA13, VPOG3); + +#define L20 212 +#define L20_DESC SIG_DESC_SET(SCUA4, 28) +SIG_EXPR_DECL(ROMA14, ROM8, L20_DESC, VPO_24_OFF); +SIG_EXPR_DECL(ROMA14, ROM16, L20_DESC, VPO_24_OFF); +SIG_EXPR_LIST_DECL_DUAL(ROMA14, ROM8, ROM16); +SIG_EXPR_DECL(VPOG4, VPO24, L20_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOG4, VPOOFF1, L20_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL_DUAL(VPOG4, VPO24, VPOOFF1); +MS_PIN_DECL(L20, GPIOAA4, ROMA14, VPOG4); + +#define L21 213 +#define L21_DESC SIG_DESC_SET(SCUA4, 29) +SIG_EXPR_DECL(ROMA15, ROM8, L21_DESC, VPO_24_OFF); +SIG_EXPR_DECL(ROMA15, ROM16, L21_DESC, VPO_24_OFF); +SIG_EXPR_LIST_DECL_DUAL(ROMA15, ROM8, ROM16); +SIG_EXPR_DECL(VPOG5, VPO24, L21_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOG5, VPOOFF1, L21_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL_DUAL(VPOG5, VPO24, VPOOFF1); +MS_PIN_DECL(L21, GPIOAA5, ROMA15, VPOG5); + +#define T18 214 +#define T18_DESC SIG_DESC_SET(SCUA4, 30) +SIG_EXPR_DECL(ROMA16, ROM8, T18_DESC, VPO_24_OFF); +SIG_EXPR_DECL(ROMA16, ROM16, T18_DESC, VPO_24_OFF); +SIG_EXPR_LIST_DECL_DUAL(ROMA16, ROM8, ROM16); +SIG_EXPR_DECL(VPOG6, VPO24, T18_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOG6, VPOOFF1, T18_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL_DUAL(VPOG6, VPO24, VPOOFF1); +MS_PIN_DECL(T18, GPIOAA6, ROMA16, VPOG6); + +#define N18 215 +#define N18_DESC SIG_DESC_SET(SCUA4, 31) +SIG_EXPR_DECL(ROMA17, ROM8, N18_DESC, VPO_24_OFF); +SIG_EXPR_DECL(ROMA17, ROM16, N18_DESC, VPO_24_OFF); +SIG_EXPR_LIST_DECL_DUAL(ROMA17, ROM8, ROM16); +SIG_EXPR_DECL(VPOG7, VPO24, N18_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOG7, VPOOFF1, N18_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL_DUAL(VPOG7, VPO24, VPOOFF1); +MS_PIN_DECL(N18, GPIOAA7, ROMA17, VPOG7); + +#define N19 216 +#define N19_DESC SIG_DESC_SET(SCUA8, 0) +SIG_EXPR_DECL(ROMA18, ROM8, N19_DESC, VPO_24_OFF); +SIG_EXPR_DECL(ROMA18, ROM16, N19_DESC, VPO_24_OFF); +SIG_EXPR_LIST_DECL_DUAL(ROMA18, ROM8, ROM16); +SIG_EXPR_DECL(VPOR0, VPO24, N19_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOR0, VPOOFF1, N19_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL_DUAL(VPOR0, VPO24, VPOOFF1); +MS_PIN_DECL(N19, GPIOAB0, ROMA18, VPOR0); + +#define M18 217 +#define M18_DESC SIG_DESC_SET(SCUA8, 1) +SIG_EXPR_DECL(ROMA19, ROM8, M18_DESC, VPO_24_OFF); +SIG_EXPR_DECL(ROMA19, ROM16, M18_DESC, VPO_24_OFF); +SIG_EXPR_LIST_DECL_DUAL(ROMA19, ROM8, ROM16); +SIG_EXPR_DECL(VPOR1, VPO24, M18_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOR1, VPOOFF1, M18_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL_DUAL(VPOR1, VPO24, VPOOFF1); +MS_PIN_DECL(M18, GPIOAB1, ROMA19, VPOR1); + +#define N22 218 +#define N22_DESC SIG_DESC_SET(SCUA8, 2) +SIG_EXPR_DECL(ROMA20, ROM8, N22_DESC, VPO_24_OFF); +SIG_EXPR_DECL(ROMA20, ROM16, N22_DESC, VPO_24_OFF); +SIG_EXPR_LIST_DECL_DUAL(ROMA20, ROM8, ROM16); +SIG_EXPR_DECL(VPOR2, VPO24, N22_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOR2, VPOOFF1, N22_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL_DUAL(VPOR2, VPO24, VPOOFF1); +MS_PIN_DECL(N22, GPIOAB2, ROMA20, VPOR2); + +#define N20 219 +#define N20_DESC SIG_DESC_SET(SCUA8, 3) +SIG_EXPR_DECL(ROMA21, ROM8, N20_DESC, VPO_24_OFF); +SIG_EXPR_DECL(ROMA21, ROM16, N20_DESC, VPO_24_OFF); +SIG_EXPR_LIST_DECL_DUAL(ROMA21, ROM8, ROM16); +SIG_EXPR_DECL(VPOR3, VPO24, N20_DESC, VPO24_DESC); +SIG_EXPR_DECL(VPOR3, VPOOFF1, N20_DESC, VPOOFF1_DESC); +SIG_EXPR_LIST_DECL_DUAL(VPOR3, VPO24, VPOOFF1); +MS_PIN_DECL(N20, GPIOAB3, ROMA21, VPOR3); + +FUNC_GROUP_DECL(ROM8, V20, U21, T19, V22, U20, R18, N21, L22, K18, W21, Y22, + U19, R22, P18, P19, P20, P21, P22, M19, M20, M21, M22, L18, + L19, L20, L21, T18, N18, N19, M18, N22, N20); +FUNC_GROUP_DECL(ROM16, V20, U21, T19, V22, U20, R18, N21, L22, K18, + A8, C7, B7, A7, D7, B6, A6, E7, W21, Y22, U19, R22, P18, P19, + P20, P21, P22, M19, M20, M21, M22, L18, L19, L20, L21, T18, + N18, N19, M18, N22, N20); +FUNC_GROUP_DECL(VPO12, U21, T19, V22, U20, R22, P18, P19, P20, P21, P22, M19, + M20, M21, M22, L18, L19, L20, L21, T18, N18, N19, M18, N22, + N20); +FUNC_GROUP_DECL(VPO24, U21, T19, V22, U20, L22, K18, V21, W22, R22, P18, P19, + P20, P21, P22, M19, M20, M21, M22, L18, L19); + /* Note we account for GPIOY4-GPIOY7 even though they're not valid, thus 216 * pins becomes 220. */ @@ -883,84 +1715,180 @@ FUNC_GROUP_DECL(RGMII1, A12, B12, C12, D12, E12, A13, E11, D11, C11, B11, A11, static struct pinctrl_pin_desc aspeed_g4_pins[ASPEED_G4_NR_PINS] = { ASPEED_PINCTRL_PIN(A1), + ASPEED_PINCTRL_PIN(A10), ASPEED_PINCTRL_PIN(A11), ASPEED_PINCTRL_PIN(A12), ASPEED_PINCTRL_PIN(A13), + ASPEED_PINCTRL_PIN(A14), ASPEED_PINCTRL_PIN(A15), + ASPEED_PINCTRL_PIN(A16), + ASPEED_PINCTRL_PIN(A17), ASPEED_PINCTRL_PIN(A18), + ASPEED_PINCTRL_PIN(A19), ASPEED_PINCTRL_PIN(A2), + ASPEED_PINCTRL_PIN(A20), ASPEED_PINCTRL_PIN(A3), ASPEED_PINCTRL_PIN(A4), ASPEED_PINCTRL_PIN(A5), ASPEED_PINCTRL_PIN(A6), ASPEED_PINCTRL_PIN(A7), ASPEED_PINCTRL_PIN(A8), + ASPEED_PINCTRL_PIN(A9), + ASPEED_PINCTRL_PIN(AA1), ASPEED_PINCTRL_PIN(AA2), ASPEED_PINCTRL_PIN(AA22), ASPEED_PINCTRL_PIN(AA3), + ASPEED_PINCTRL_PIN(AA4), + ASPEED_PINCTRL_PIN(AA5), + ASPEED_PINCTRL_PIN(AA6), ASPEED_PINCTRL_PIN(AA7), ASPEED_PINCTRL_PIN(AB1), ASPEED_PINCTRL_PIN(AB2), + ASPEED_PINCTRL_PIN(AB3), + ASPEED_PINCTRL_PIN(AB4), + ASPEED_PINCTRL_PIN(AB5), + ASPEED_PINCTRL_PIN(AB6), ASPEED_PINCTRL_PIN(AB7), ASPEED_PINCTRL_PIN(B1), + ASPEED_PINCTRL_PIN(B10), ASPEED_PINCTRL_PIN(B11), ASPEED_PINCTRL_PIN(B12), + ASPEED_PINCTRL_PIN(B13), ASPEED_PINCTRL_PIN(B14), ASPEED_PINCTRL_PIN(B15), + ASPEED_PINCTRL_PIN(B16), + ASPEED_PINCTRL_PIN(B17), + ASPEED_PINCTRL_PIN(B18), ASPEED_PINCTRL_PIN(B19), ASPEED_PINCTRL_PIN(B2), + ASPEED_PINCTRL_PIN(B22), ASPEED_PINCTRL_PIN(B3), ASPEED_PINCTRL_PIN(B4), + ASPEED_PINCTRL_PIN(B5), ASPEED_PINCTRL_PIN(B6), ASPEED_PINCTRL_PIN(B7), + ASPEED_PINCTRL_PIN(B9), ASPEED_PINCTRL_PIN(C1), + ASPEED_PINCTRL_PIN(C10), ASPEED_PINCTRL_PIN(C11), ASPEED_PINCTRL_PIN(C12), + ASPEED_PINCTRL_PIN(C13), ASPEED_PINCTRL_PIN(C14), ASPEED_PINCTRL_PIN(C15), + ASPEED_PINCTRL_PIN(C16), ASPEED_PINCTRL_PIN(C17), + ASPEED_PINCTRL_PIN(C18), ASPEED_PINCTRL_PIN(C2), + ASPEED_PINCTRL_PIN(C20), + ASPEED_PINCTRL_PIN(C21), + ASPEED_PINCTRL_PIN(C22), ASPEED_PINCTRL_PIN(C3), ASPEED_PINCTRL_PIN(C4), ASPEED_PINCTRL_PIN(C5), ASPEED_PINCTRL_PIN(C6), ASPEED_PINCTRL_PIN(C7), + ASPEED_PINCTRL_PIN(C8), + ASPEED_PINCTRL_PIN(C9), ASPEED_PINCTRL_PIN(D1), + ASPEED_PINCTRL_PIN(D10), ASPEED_PINCTRL_PIN(D11), ASPEED_PINCTRL_PIN(D12), + ASPEED_PINCTRL_PIN(D13), ASPEED_PINCTRL_PIN(D14), ASPEED_PINCTRL_PIN(D15), ASPEED_PINCTRL_PIN(D16), ASPEED_PINCTRL_PIN(D17), ASPEED_PINCTRL_PIN(D18), + ASPEED_PINCTRL_PIN(D19), ASPEED_PINCTRL_PIN(D2), ASPEED_PINCTRL_PIN(D3), ASPEED_PINCTRL_PIN(D4), ASPEED_PINCTRL_PIN(D5), + ASPEED_PINCTRL_PIN(D6), ASPEED_PINCTRL_PIN(D7), + ASPEED_PINCTRL_PIN(D8), + ASPEED_PINCTRL_PIN(D9), ASPEED_PINCTRL_PIN(E10), ASPEED_PINCTRL_PIN(E11), ASPEED_PINCTRL_PIN(E12), + ASPEED_PINCTRL_PIN(E13), ASPEED_PINCTRL_PIN(E14), + ASPEED_PINCTRL_PIN(E15), ASPEED_PINCTRL_PIN(E16), + ASPEED_PINCTRL_PIN(E18), + ASPEED_PINCTRL_PIN(E19), ASPEED_PINCTRL_PIN(E2), + ASPEED_PINCTRL_PIN(E20), ASPEED_PINCTRL_PIN(E3), ASPEED_PINCTRL_PIN(E5), + ASPEED_PINCTRL_PIN(E6), ASPEED_PINCTRL_PIN(E7), + ASPEED_PINCTRL_PIN(E8), + ASPEED_PINCTRL_PIN(E9), + ASPEED_PINCTRL_PIN(F18), + ASPEED_PINCTRL_PIN(F20), ASPEED_PINCTRL_PIN(F3), ASPEED_PINCTRL_PIN(F4), ASPEED_PINCTRL_PIN(F5), + ASPEED_PINCTRL_PIN(G18), + ASPEED_PINCTRL_PIN(G19), + ASPEED_PINCTRL_PIN(G20), ASPEED_PINCTRL_PIN(G5), ASPEED_PINCTRL_PIN(H1), + ASPEED_PINCTRL_PIN(H18), ASPEED_PINCTRL_PIN(H19), ASPEED_PINCTRL_PIN(H2), ASPEED_PINCTRL_PIN(H20), + ASPEED_PINCTRL_PIN(H3), + ASPEED_PINCTRL_PIN(H4), + ASPEED_PINCTRL_PIN(J20), + ASPEED_PINCTRL_PIN(J21), ASPEED_PINCTRL_PIN(J3), + ASPEED_PINCTRL_PIN(J4), + ASPEED_PINCTRL_PIN(J5), ASPEED_PINCTRL_PIN(K18), + ASPEED_PINCTRL_PIN(K20), + ASPEED_PINCTRL_PIN(K5), + ASPEED_PINCTRL_PIN(L1), + ASPEED_PINCTRL_PIN(L18), + ASPEED_PINCTRL_PIN(L19), + ASPEED_PINCTRL_PIN(L2), + ASPEED_PINCTRL_PIN(L20), + ASPEED_PINCTRL_PIN(L21), ASPEED_PINCTRL_PIN(L22), + ASPEED_PINCTRL_PIN(L3), + ASPEED_PINCTRL_PIN(L4), + ASPEED_PINCTRL_PIN(L5), + ASPEED_PINCTRL_PIN(M1), + ASPEED_PINCTRL_PIN(M18), + ASPEED_PINCTRL_PIN(M19), + ASPEED_PINCTRL_PIN(M2), + ASPEED_PINCTRL_PIN(M20), + ASPEED_PINCTRL_PIN(M21), + ASPEED_PINCTRL_PIN(M22), + ASPEED_PINCTRL_PIN(M3), + ASPEED_PINCTRL_PIN(M4), + ASPEED_PINCTRL_PIN(M5), + ASPEED_PINCTRL_PIN(N1), + ASPEED_PINCTRL_PIN(N18), + ASPEED_PINCTRL_PIN(N19), + ASPEED_PINCTRL_PIN(N2), + ASPEED_PINCTRL_PIN(N20), ASPEED_PINCTRL_PIN(N21), + ASPEED_PINCTRL_PIN(N22), + ASPEED_PINCTRL_PIN(N3), + ASPEED_PINCTRL_PIN(N4), + ASPEED_PINCTRL_PIN(N5), + ASPEED_PINCTRL_PIN(P18), + ASPEED_PINCTRL_PIN(P19), + ASPEED_PINCTRL_PIN(P20), + ASPEED_PINCTRL_PIN(P21), + ASPEED_PINCTRL_PIN(P22), + ASPEED_PINCTRL_PIN(P5), ASPEED_PINCTRL_PIN(R18), + ASPEED_PINCTRL_PIN(R22), ASPEED_PINCTRL_PIN(T1), + ASPEED_PINCTRL_PIN(T18), ASPEED_PINCTRL_PIN(T19), ASPEED_PINCTRL_PIN(T2), ASPEED_PINCTRL_PIN(T4), @@ -979,28 +1907,61 @@ static struct pinctrl_pin_desc aspeed_g4_pins[ASPEED_G4_NR_PINS] = { ASPEED_PINCTRL_PIN(V20), ASPEED_PINCTRL_PIN(V21), ASPEED_PINCTRL_PIN(V22), + ASPEED_PINCTRL_PIN(V3), + ASPEED_PINCTRL_PIN(V4), + ASPEED_PINCTRL_PIN(V5), ASPEED_PINCTRL_PIN(V6), + ASPEED_PINCTRL_PIN(V7), ASPEED_PINCTRL_PIN(W1), + ASPEED_PINCTRL_PIN(W2), ASPEED_PINCTRL_PIN(W21), ASPEED_PINCTRL_PIN(W22), + ASPEED_PINCTRL_PIN(W3), ASPEED_PINCTRL_PIN(W4), ASPEED_PINCTRL_PIN(W5), + ASPEED_PINCTRL_PIN(W6), + ASPEED_PINCTRL_PIN(W7), + ASPEED_PINCTRL_PIN(Y1), + ASPEED_PINCTRL_PIN(Y2), + ASPEED_PINCTRL_PIN(Y21), ASPEED_PINCTRL_PIN(Y22), ASPEED_PINCTRL_PIN(Y3), ASPEED_PINCTRL_PIN(Y4), ASPEED_PINCTRL_PIN(Y5), + ASPEED_PINCTRL_PIN(Y6), ASPEED_PINCTRL_PIN(Y7), }; static const struct aspeed_pin_group aspeed_g4_groups[] = { ASPEED_PINCTRL_GROUP(ACPI), + ASPEED_PINCTRL_GROUP(ADC0), + ASPEED_PINCTRL_GROUP(ADC1), + ASPEED_PINCTRL_GROUP(ADC10), + ASPEED_PINCTRL_GROUP(ADC11), + ASPEED_PINCTRL_GROUP(ADC12), + ASPEED_PINCTRL_GROUP(ADC13), + ASPEED_PINCTRL_GROUP(ADC14), + ASPEED_PINCTRL_GROUP(ADC15), + ASPEED_PINCTRL_GROUP(ADC2), + ASPEED_PINCTRL_GROUP(ADC3), + ASPEED_PINCTRL_GROUP(ADC4), + ASPEED_PINCTRL_GROUP(ADC5), + ASPEED_PINCTRL_GROUP(ADC6), + ASPEED_PINCTRL_GROUP(ADC7), + ASPEED_PINCTRL_GROUP(ADC8), + ASPEED_PINCTRL_GROUP(ADC9), ASPEED_PINCTRL_GROUP(BMCINT), ASPEED_PINCTRL_GROUP(DDCCLK), ASPEED_PINCTRL_GROUP(DDCDAT), + ASPEED_PINCTRL_GROUP(EXTRST), ASPEED_PINCTRL_GROUP(FLACK), ASPEED_PINCTRL_GROUP(FLBUSY), ASPEED_PINCTRL_GROUP(FLWP), + ASPEED_PINCTRL_GROUP(GPID), ASPEED_PINCTRL_GROUP(GPID0), + ASPEED_PINCTRL_GROUP(GPID2), + ASPEED_PINCTRL_GROUP(GPID4), + ASPEED_PINCTRL_GROUP(GPID6), ASPEED_PINCTRL_GROUP(GPIE0), ASPEED_PINCTRL_GROUP(GPIE2), ASPEED_PINCTRL_GROUP(GPIE4), @@ -1009,6 +1970,7 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = { ASPEED_PINCTRL_GROUP(I2C11), ASPEED_PINCTRL_GROUP(I2C12), ASPEED_PINCTRL_GROUP(I2C13), + ASPEED_PINCTRL_GROUP(I2C14), ASPEED_PINCTRL_GROUP(I2C3), ASPEED_PINCTRL_GROUP(I2C4), ASPEED_PINCTRL_GROUP(I2C5), @@ -1018,25 +1980,37 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = { ASPEED_PINCTRL_GROUP(I2C9), ASPEED_PINCTRL_GROUP(LPCPD), ASPEED_PINCTRL_GROUP(LPCPME), - ASPEED_PINCTRL_GROUP(LPCPME), + ASPEED_PINCTRL_GROUP(LPCRST), ASPEED_PINCTRL_GROUP(LPCSMI), + ASPEED_PINCTRL_GROUP(MAC1LINK), + ASPEED_PINCTRL_GROUP(MAC2LINK), ASPEED_PINCTRL_GROUP(MDIO1), ASPEED_PINCTRL_GROUP(MDIO2), ASPEED_PINCTRL_GROUP(NCTS1), + ASPEED_PINCTRL_GROUP(NCTS2), ASPEED_PINCTRL_GROUP(NCTS3), ASPEED_PINCTRL_GROUP(NCTS4), ASPEED_PINCTRL_GROUP(NDCD1), + ASPEED_PINCTRL_GROUP(NDCD2), ASPEED_PINCTRL_GROUP(NDCD3), ASPEED_PINCTRL_GROUP(NDCD4), ASPEED_PINCTRL_GROUP(NDSR1), + ASPEED_PINCTRL_GROUP(NDSR2), ASPEED_PINCTRL_GROUP(NDSR3), + ASPEED_PINCTRL_GROUP(NDSR4), ASPEED_PINCTRL_GROUP(NDTR1), + ASPEED_PINCTRL_GROUP(NDTR2), ASPEED_PINCTRL_GROUP(NDTR3), + ASPEED_PINCTRL_GROUP(NDTR4), + ASPEED_PINCTRL_GROUP(NDTS4), ASPEED_PINCTRL_GROUP(NRI1), + ASPEED_PINCTRL_GROUP(NRI2), ASPEED_PINCTRL_GROUP(NRI3), ASPEED_PINCTRL_GROUP(NRI4), ASPEED_PINCTRL_GROUP(NRTS1), + ASPEED_PINCTRL_GROUP(NRTS2), ASPEED_PINCTRL_GROUP(NRTS3), + ASPEED_PINCTRL_GROUP(OSCCLK), ASPEED_PINCTRL_GROUP(PWM0), ASPEED_PINCTRL_GROUP(PWM1), ASPEED_PINCTRL_GROUP(PWM2), @@ -1046,7 +2020,9 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = { ASPEED_PINCTRL_GROUP(PWM6), ASPEED_PINCTRL_GROUP(PWM7), ASPEED_PINCTRL_GROUP(RGMII1), + ASPEED_PINCTRL_GROUP(RGMII2), ASPEED_PINCTRL_GROUP(RMII1), + ASPEED_PINCTRL_GROUP(RMII2), ASPEED_PINCTRL_GROUP(ROM16), ASPEED_PINCTRL_GROUP(ROM8), ASPEED_PINCTRL_GROUP(ROMCS1), @@ -1054,21 +2030,48 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = { ASPEED_PINCTRL_GROUP(ROMCS3), ASPEED_PINCTRL_GROUP(ROMCS4), ASPEED_PINCTRL_GROUP(RXD1), + ASPEED_PINCTRL_GROUP(RXD2), ASPEED_PINCTRL_GROUP(RXD3), ASPEED_PINCTRL_GROUP(RXD4), + ASPEED_PINCTRL_GROUP(SALT1), + ASPEED_PINCTRL_GROUP(SALT2), + ASPEED_PINCTRL_GROUP(SALT3), + ASPEED_PINCTRL_GROUP(SALT4), ASPEED_PINCTRL_GROUP(SD1), + ASPEED_PINCTRL_GROUP(SD2), + ASPEED_PINCTRL_GROUP(SGPMCK), ASPEED_PINCTRL_GROUP(SGPMI), + ASPEED_PINCTRL_GROUP(SGPMLD), + ASPEED_PINCTRL_GROUP(SGPMO), + ASPEED_PINCTRL_GROUP(SGPSCK), + ASPEED_PINCTRL_GROUP(SGPSI0), + ASPEED_PINCTRL_GROUP(SGPSI1), + ASPEED_PINCTRL_GROUP(SGPSLD), + ASPEED_PINCTRL_GROUP(SIOONCTRL), ASPEED_PINCTRL_GROUP(SIOPBI), ASPEED_PINCTRL_GROUP(SIOPBO), + ASPEED_PINCTRL_GROUP(SIOPWREQ), + ASPEED_PINCTRL_GROUP(SIOPWRGD), + ASPEED_PINCTRL_GROUP(SIOS3), + ASPEED_PINCTRL_GROUP(SIOS5), + ASPEED_PINCTRL_GROUP(SIOSCI), + ASPEED_PINCTRL_GROUP(SPI1), + ASPEED_PINCTRL_GROUP(SPI1DEBUG), + ASPEED_PINCTRL_GROUP(SPI1PASSTHRU), + ASPEED_PINCTRL_GROUP(SPICS1), ASPEED_PINCTRL_GROUP(TIMER3), + ASPEED_PINCTRL_GROUP(TIMER4), ASPEED_PINCTRL_GROUP(TIMER5), ASPEED_PINCTRL_GROUP(TIMER6), ASPEED_PINCTRL_GROUP(TIMER7), ASPEED_PINCTRL_GROUP(TIMER8), ASPEED_PINCTRL_GROUP(TXD1), + ASPEED_PINCTRL_GROUP(TXD2), ASPEED_PINCTRL_GROUP(TXD3), ASPEED_PINCTRL_GROUP(TXD4), ASPEED_PINCTRL_GROUP(UART6), + ASPEED_PINCTRL_GROUP(USBCKI), + ASPEED_PINCTRL_GROUP(VGABIOS_ROM), ASPEED_PINCTRL_GROUP(VGAHS), ASPEED_PINCTRL_GROUP(VGAVS), ASPEED_PINCTRL_GROUP(VPI18), @@ -1076,17 +2079,40 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = { ASPEED_PINCTRL_GROUP(VPI30), ASPEED_PINCTRL_GROUP(VPO12), ASPEED_PINCTRL_GROUP(VPO24), + ASPEED_PINCTRL_GROUP(WDTRST1), + ASPEED_PINCTRL_GROUP(WDTRST2), }; static const struct aspeed_pin_function aspeed_g4_functions[] = { ASPEED_PINCTRL_FUNC(ACPI), + ASPEED_PINCTRL_FUNC(ADC0), + ASPEED_PINCTRL_FUNC(ADC1), + ASPEED_PINCTRL_FUNC(ADC10), + ASPEED_PINCTRL_FUNC(ADC11), + ASPEED_PINCTRL_FUNC(ADC12), + ASPEED_PINCTRL_FUNC(ADC13), + ASPEED_PINCTRL_FUNC(ADC14), + ASPEED_PINCTRL_FUNC(ADC15), + ASPEED_PINCTRL_FUNC(ADC2), + ASPEED_PINCTRL_FUNC(ADC3), + ASPEED_PINCTRL_FUNC(ADC4), + ASPEED_PINCTRL_FUNC(ADC5), + ASPEED_PINCTRL_FUNC(ADC6), + ASPEED_PINCTRL_FUNC(ADC7), + ASPEED_PINCTRL_FUNC(ADC8), + ASPEED_PINCTRL_FUNC(ADC9), ASPEED_PINCTRL_FUNC(BMCINT), ASPEED_PINCTRL_FUNC(DDCCLK), ASPEED_PINCTRL_FUNC(DDCDAT), + ASPEED_PINCTRL_FUNC(EXTRST), ASPEED_PINCTRL_FUNC(FLACK), ASPEED_PINCTRL_FUNC(FLBUSY), ASPEED_PINCTRL_FUNC(FLWP), + ASPEED_PINCTRL_FUNC(GPID), ASPEED_PINCTRL_FUNC(GPID0), + ASPEED_PINCTRL_FUNC(GPID2), + ASPEED_PINCTRL_FUNC(GPID4), + ASPEED_PINCTRL_FUNC(GPID6), ASPEED_PINCTRL_FUNC(GPIE0), ASPEED_PINCTRL_FUNC(GPIE2), ASPEED_PINCTRL_FUNC(GPIE4), @@ -1095,6 +2121,7 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { ASPEED_PINCTRL_FUNC(I2C11), ASPEED_PINCTRL_FUNC(I2C12), ASPEED_PINCTRL_FUNC(I2C13), + ASPEED_PINCTRL_FUNC(I2C14), ASPEED_PINCTRL_FUNC(I2C3), ASPEED_PINCTRL_FUNC(I2C4), ASPEED_PINCTRL_FUNC(I2C5), @@ -1104,24 +2131,37 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { ASPEED_PINCTRL_FUNC(I2C9), ASPEED_PINCTRL_FUNC(LPCPD), ASPEED_PINCTRL_FUNC(LPCPME), + ASPEED_PINCTRL_FUNC(LPCRST), ASPEED_PINCTRL_FUNC(LPCSMI), + ASPEED_PINCTRL_FUNC(MAC1LINK), + ASPEED_PINCTRL_FUNC(MAC2LINK), ASPEED_PINCTRL_FUNC(MDIO1), ASPEED_PINCTRL_FUNC(MDIO2), ASPEED_PINCTRL_FUNC(NCTS1), + ASPEED_PINCTRL_FUNC(NCTS2), ASPEED_PINCTRL_FUNC(NCTS3), ASPEED_PINCTRL_FUNC(NCTS4), ASPEED_PINCTRL_FUNC(NDCD1), + ASPEED_PINCTRL_FUNC(NDCD2), ASPEED_PINCTRL_FUNC(NDCD3), ASPEED_PINCTRL_FUNC(NDCD4), ASPEED_PINCTRL_FUNC(NDSR1), + ASPEED_PINCTRL_FUNC(NDSR2), ASPEED_PINCTRL_FUNC(NDSR3), + ASPEED_PINCTRL_FUNC(NDSR4), ASPEED_PINCTRL_FUNC(NDTR1), + ASPEED_PINCTRL_FUNC(NDTR2), ASPEED_PINCTRL_FUNC(NDTR3), + ASPEED_PINCTRL_FUNC(NDTR4), + ASPEED_PINCTRL_FUNC(NDTS4), ASPEED_PINCTRL_FUNC(NRI1), + ASPEED_PINCTRL_FUNC(NRI2), ASPEED_PINCTRL_FUNC(NRI3), ASPEED_PINCTRL_FUNC(NRI4), ASPEED_PINCTRL_FUNC(NRTS1), + ASPEED_PINCTRL_FUNC(NRTS2), ASPEED_PINCTRL_FUNC(NRTS3), + ASPEED_PINCTRL_FUNC(OSCCLK), ASPEED_PINCTRL_FUNC(PWM0), ASPEED_PINCTRL_FUNC(PWM1), ASPEED_PINCTRL_FUNC(PWM2), @@ -1131,7 +2171,9 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { ASPEED_PINCTRL_FUNC(PWM6), ASPEED_PINCTRL_FUNC(PWM7), ASPEED_PINCTRL_FUNC(RGMII1), + ASPEED_PINCTRL_FUNC(RGMII2), ASPEED_PINCTRL_FUNC(RMII1), + ASPEED_PINCTRL_FUNC(RMII2), ASPEED_PINCTRL_FUNC(ROM16), ASPEED_PINCTRL_FUNC(ROM8), ASPEED_PINCTRL_FUNC(ROMCS1), @@ -1139,21 +2181,48 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { ASPEED_PINCTRL_FUNC(ROMCS3), ASPEED_PINCTRL_FUNC(ROMCS4), ASPEED_PINCTRL_FUNC(RXD1), + ASPEED_PINCTRL_FUNC(RXD2), ASPEED_PINCTRL_FUNC(RXD3), ASPEED_PINCTRL_FUNC(RXD4), + ASPEED_PINCTRL_FUNC(SALT1), + ASPEED_PINCTRL_FUNC(SALT2), + ASPEED_PINCTRL_FUNC(SALT3), + ASPEED_PINCTRL_FUNC(SALT4), ASPEED_PINCTRL_FUNC(SD1), + ASPEED_PINCTRL_FUNC(SD2), + ASPEED_PINCTRL_FUNC(SGPMCK), ASPEED_PINCTRL_FUNC(SGPMI), + ASPEED_PINCTRL_FUNC(SGPMLD), + ASPEED_PINCTRL_FUNC(SGPMO), + ASPEED_PINCTRL_FUNC(SGPSCK), + ASPEED_PINCTRL_FUNC(SGPSI0), + ASPEED_PINCTRL_FUNC(SGPSI1), + ASPEED_PINCTRL_FUNC(SGPSLD), + ASPEED_PINCTRL_FUNC(SIOONCTRL), ASPEED_PINCTRL_FUNC(SIOPBI), ASPEED_PINCTRL_FUNC(SIOPBO), + ASPEED_PINCTRL_FUNC(SIOPWREQ), + ASPEED_PINCTRL_FUNC(SIOPWRGD), + ASPEED_PINCTRL_FUNC(SIOS3), + ASPEED_PINCTRL_FUNC(SIOS5), + ASPEED_PINCTRL_FUNC(SIOSCI), + ASPEED_PINCTRL_FUNC(SPI1), + ASPEED_PINCTRL_FUNC(SPI1DEBUG), + ASPEED_PINCTRL_FUNC(SPI1PASSTHRU), + ASPEED_PINCTRL_FUNC(SPICS1), ASPEED_PINCTRL_FUNC(TIMER3), + ASPEED_PINCTRL_FUNC(TIMER4), ASPEED_PINCTRL_FUNC(TIMER5), ASPEED_PINCTRL_FUNC(TIMER6), ASPEED_PINCTRL_FUNC(TIMER7), ASPEED_PINCTRL_FUNC(TIMER8), ASPEED_PINCTRL_FUNC(TXD1), + ASPEED_PINCTRL_FUNC(TXD2), ASPEED_PINCTRL_FUNC(TXD3), ASPEED_PINCTRL_FUNC(TXD4), ASPEED_PINCTRL_FUNC(UART6), + ASPEED_PINCTRL_FUNC(USBCKI), + ASPEED_PINCTRL_FUNC(VGABIOS_ROM), ASPEED_PINCTRL_FUNC(VGAHS), ASPEED_PINCTRL_FUNC(VGAVS), ASPEED_PINCTRL_FUNC(VPI18), @@ -1161,6 +2230,8 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { ASPEED_PINCTRL_FUNC(VPI30), ASPEED_PINCTRL_FUNC(VPO12), ASPEED_PINCTRL_FUNC(VPO24), + ASPEED_PINCTRL_FUNC(WDTRST1), + ASPEED_PINCTRL_FUNC(WDTRST2), }; static struct aspeed_pinctrl_data aspeed_g4_pinctrl_data = { From f1337856dd88858bf58bd062306ccbfb63303085 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Tue, 20 Dec 2016 18:05:50 +1030 Subject: [PATCH 0027/1587] pinctrl: aspeed-g5: Add mux configuration for all pins The patch introducing the g5 pinctrl driver implemented a smattering of pins to flesh out the implementation of the core and provide bare-bones support for some OpenPOWER platforms and the AST2500 evaluation board. Now, update the bindings document to reflect the complete functionality and implement the necessary pin configuration tables in the driver. Signed-off-by: Andrew Jeffery Acked-by: Joel Stanley Acked-by: Rob Herring Signed-off-by: Linus Walleij --- .../bindings/pinctrl/pinctrl-aspeed.txt | 17 +- drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 1476 ++++++++++++++++- drivers/pinctrl/aspeed/pinctrl-aspeed.h | 1 + 3 files changed, 1487 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt index a645d0be3347..b98e6f030da8 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt @@ -59,10 +59,19 @@ VGAVS VPI18 VPI24 VPI30 VPO12 VPO24 WDTRST1 WDTRST2 aspeed,ast2500-pinctrl, aspeed,g5-pinctrl: -GPID0 GPID2 GPIE0 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8 -I2C9 MAC1LINK MDIO1 MDIO2 OSCCLK PEWAKE PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 -RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 SPI1DEBUG SPI1PASSTHRU TIMER4 TIMER5 TIMER6 -TIMER7 TIMER8 VGABIOSROM +ACPI ADC0 ADC1 ADC10 ADC11 ADC12 ADC13 ADC14 ADC15 ADC2 ADC3 ADC4 ADC5 ADC6 +ADC7 ADC8 ADC9 BMCINT DDCCLK DDCDAT ESPI FWSPICS1 FWSPICS2 GPID0 GPID2 GPID4 +GPID6 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6 +I2C7 I2C8 I2C9 LAD0 LAD1 LAD2 LAD3 LCLK LFRAME LPCHC LPCPD LPCPLUS LPCPME +LPCRST LPCSMI LSIRQ MAC1LINK MAC2LINK MDIO1 MDIO2 NCTS1 NCTS2 NCTS3 NCTS4 NDCD1 +NDCD2 NDCD3 NDCD4 NDSR1 NDSR2 NDSR3 NDSR4 NDTR1 NDTR2 NDTR3 NDTR4 NRI1 NRI2 +NRI3 NRI4 NRTS1 NRTS2 NRTS3 NRTS4 OSCCLK PEWAKE PNOR PWM0 PWM1 PWM2 PWM3 PWM4 +PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 RXD1 RXD2 RXD3 RXD4 SALT1 SALT10 +SALT11 SALT12 SALT13 SALT14 SALT2 SALT3 SALT4 SALT5 SALT6 SALT7 SALT8 SALT9 +SCL1 SCL2 SD1 SD2 SDA1 SDA2 SGPS1 SGPS2 SIOONCTRL SIOPBI SIOPBO SIOPWREQ +SIOPWRGD SIOS3 SIOS5 SIOSCI SPI1 SPI1CS1 SPI1DEBUG SPI1PASSTHRU SPI2CK SPI2CS0 +SPI2CS1 SPI2MISO SPI2MOSI TIMER3 TIMER4 TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD2 +TXD3 TXD4 UART6 USBCKI VGABIOSROM VGAHS VGAVS VPI24 VPO WDTRST1 WDTRST2 Examples ======== diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index c5c9a1b6fa1c..43221a3c7e23 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -25,14 +25,28 @@ #include "../pinctrl-utils.h" #include "pinctrl-aspeed.h" -#define ASPEED_G5_NR_PINS 228 +#define ASPEED_G5_NR_PINS 232 #define COND1 { ASPEED_IP_SCU, SCU90, BIT(6), 0, 0 } #define COND2 { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 0, 0 } +/* LHCR0 is offset from the end of the H8S/2168-compatible registers */ +#define LHCR0 0x20 +#define GFX064 0x64 + #define B14 0 SSSF_PIN_DECL(B14, GPIOA0, MAC1LINK, SIG_DESC_SET(SCU80, 0)); +#define D14 1 +SSSF_PIN_DECL(D14, GPIOA1, MAC2LINK, SIG_DESC_SET(SCU80, 1)); + +#define D13 2 +SIG_EXPR_LIST_DECL_SINGLE(SPI1CS1, SPI1CS1, SIG_DESC_SET(SCU80, 15)); +SIG_EXPR_LIST_DECL_SINGLE(TIMER3, TIMER3, SIG_DESC_SET(SCU80, 2)); +MS_PIN_DECL(D13, GPIOA2, SPI1CS1, TIMER3); +FUNC_GROUP_DECL(SPI1CS1, D13); +FUNC_GROUP_DECL(TIMER3, D13); + #define E13 3 SSSF_PIN_DECL(E13, GPIOA3, TIMER4, SIG_DESC_SET(SCU80, 3)); @@ -72,6 +86,32 @@ FUNC_GROUP_DECL(TIMER8, B13); FUNC_GROUP_DECL(MDIO2, C13, B13); +#define K19 8 +GPIO_PIN_DECL(K19, GPIOB0); + +#define L19 9 +GPIO_PIN_DECL(L19, GPIOB1); + +#define L18 10 +GPIO_PIN_DECL(L18, GPIOB2); + +#define K18 11 +GPIO_PIN_DECL(K18, GPIOB3); + +#define J20 12 +SSSF_PIN_DECL(J20, GPIOB4, USBCKI, SIG_DESC_SET(HW_STRAP1, 23)); + +#define H21 13 +#define H21_DESC SIG_DESC_SET(SCU80, 13) +SIG_EXPR_LIST_DECL_SINGLE(LPCPD, LPCPD, H21_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LPCSMI, LPCSMI, H21_DESC); +MS_PIN_DECL(H21, GPIOB5, LPCPD, LPCSMI); +FUNC_GROUP_DECL(LPCPD, H21); +FUNC_GROUP_DECL(LPCSMI, H21); + +#define H22 14 +SSSF_PIN_DECL(H22, GPIOB6, LPCPME, SIG_DESC_SET(SCU80, 14)); + #define H20 15 GPIO_PIN_DECL(H20, GPIOB7); @@ -168,7 +208,44 @@ MS_PIN_DECL(D20, GPIOD3, SD2DAT1, GPID2OUT); FUNC_GROUP_DECL(GPID2, F20, D20); -#define GPIE_DESC SIG_DESC_SET(HW_STRAP1, 21) +#define GPID4_DESC SIG_DESC_SET(SCU8C, 10) + +#define D21 28 +SIG_EXPR_LIST_DECL_SINGLE(SD2DAT2, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID4IN, GPID4, GPID4_DESC); +SIG_EXPR_DECL(GPID4IN, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID4IN, GPID4, GPID); +MS_PIN_DECL(D21, GPIOD4, SD2DAT2, GPID4IN); + +#define E20 29 +SIG_EXPR_LIST_DECL_SINGLE(SD2DAT3, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID4OUT, GPID4, GPID4_DESC); +SIG_EXPR_DECL(GPID4OUT, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID4OUT, GPID4, GPID); +MS_PIN_DECL(E20, GPIOD5, SD2DAT3, GPID4OUT); + +FUNC_GROUP_DECL(GPID4, D21, E20); + +#define GPID6_DESC SIG_DESC_SET(SCU8C, 11) + +#define G18 30 +SIG_EXPR_LIST_DECL_SINGLE(SD2CD, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID6IN, GPID6, GPID6_DESC); +SIG_EXPR_DECL(GPID6IN, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID6IN, GPID6, GPID); +MS_PIN_DECL(G18, GPIOD6, SD2CD, GPID6IN); + +#define C21 31 +SIG_EXPR_LIST_DECL_SINGLE(SD2WP, SD2, SD2_DESC); +SIG_EXPR_DECL(GPID6OUT, GPID6, GPID6_DESC); +SIG_EXPR_DECL(GPID6OUT, GPID, GPID_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPID6OUT, GPID6, GPID); +MS_PIN_DECL(C21, GPIOD7, SD2WP, GPID6OUT); + +FUNC_GROUP_DECL(GPID6, G18, C21); +FUNC_GROUP_DECL(SD2, F19, E21, F20, D20, D21, E20, G18, C21); + +#define GPIE_DESC SIG_DESC_SET(HW_STRAP1, 22) #define GPIE0_DESC SIG_DESC_SET(SCU8C, 12) #define B20 32 @@ -177,6 +254,7 @@ SIG_EXPR_DECL(GPIE0IN, GPIE0, GPIE0_DESC); SIG_EXPR_DECL(GPIE0IN, GPIE, GPIE_DESC); SIG_EXPR_LIST_DECL_DUAL(GPIE0IN, GPIE0, GPIE); MS_PIN_DECL(B20, GPIOE0, NCTS3, GPIE0IN); +FUNC_GROUP_DECL(NCTS3, B20); #define C20 33 SIG_EXPR_LIST_DECL_SINGLE(NDCD3, NDCD3, SIG_DESC_SET(SCU80, 17)); @@ -184,9 +262,227 @@ SIG_EXPR_DECL(GPIE0OUT, GPIE0, GPIE0_DESC); SIG_EXPR_DECL(GPIE0OUT, GPIE, GPIE_DESC); SIG_EXPR_LIST_DECL_DUAL(GPIE0OUT, GPIE0, GPIE); MS_PIN_DECL(C20, GPIOE1, NDCD3, GPIE0OUT); +FUNC_GROUP_DECL(NDCD3, C20); FUNC_GROUP_DECL(GPIE0, B20, C20); +#define GPIE2_DESC SIG_DESC_SET(SCU8C, 13) + +#define F18 34 +SIG_EXPR_LIST_DECL_SINGLE(NDSR3, NDSR3, SIG_DESC_SET(SCU80, 18)); +SIG_EXPR_DECL(GPIE2IN, GPIE2, GPIE2_DESC); +SIG_EXPR_DECL(GPIE2IN, GPIE, GPIE_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPIE2IN, GPIE2, GPIE); +MS_PIN_DECL(F18, GPIOE2, NDSR3, GPIE2IN); +FUNC_GROUP_DECL(NDSR3, F18); + + +#define F17 35 +SIG_EXPR_LIST_DECL_SINGLE(NRI3, NRI3, SIG_DESC_SET(SCU80, 19)); +SIG_EXPR_DECL(GPIE2OUT, GPIE2, GPIE2_DESC); +SIG_EXPR_DECL(GPIE2OUT, GPIE, GPIE_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPIE2OUT, GPIE2, GPIE); +MS_PIN_DECL(F17, GPIOE3, NRI3, GPIE2OUT); +FUNC_GROUP_DECL(NRI3, F17); + +FUNC_GROUP_DECL(GPIE2, F18, F17); + +#define GPIE4_DESC SIG_DESC_SET(SCU8C, 14) + +#define E18 36 +SIG_EXPR_LIST_DECL_SINGLE(NDTR3, NDTR3, SIG_DESC_SET(SCU80, 20)); +SIG_EXPR_DECL(GPIE4IN, GPIE4, GPIE4_DESC); +SIG_EXPR_DECL(GPIE4IN, GPIE, GPIE_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPIE4IN, GPIE4, GPIE); +MS_PIN_DECL(E18, GPIOE4, NDTR3, GPIE4IN); +FUNC_GROUP_DECL(NDTR3, E18); + +#define D19 37 +SIG_EXPR_LIST_DECL_SINGLE(NRTS3, NRTS3, SIG_DESC_SET(SCU80, 21)); +SIG_EXPR_DECL(GPIE4OUT, GPIE4, GPIE4_DESC); +SIG_EXPR_DECL(GPIE4OUT, GPIE, GPIE_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPIE4OUT, GPIE4, GPIE); +MS_PIN_DECL(D19, GPIOE5, NRTS3, GPIE4OUT); +FUNC_GROUP_DECL(NRTS3, D19); + +FUNC_GROUP_DECL(GPIE4, E18, D19); + +#define GPIE6_DESC SIG_DESC_SET(SCU8C, 15) + +#define A20 38 +SIG_EXPR_LIST_DECL_SINGLE(TXD3, TXD3, SIG_DESC_SET(SCU80, 22)); +SIG_EXPR_DECL(GPIE6IN, GPIE6, GPIE6_DESC); +SIG_EXPR_DECL(GPIE6IN, GPIE, GPIE_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPIE6IN, GPIE6, GPIE); +MS_PIN_DECL(A20, GPIOE6, TXD3, GPIE6IN); +FUNC_GROUP_DECL(TXD3, A20); + +#define B19 39 +SIG_EXPR_LIST_DECL_SINGLE(RXD3, RXD3, SIG_DESC_SET(SCU80, 23)); +SIG_EXPR_DECL(GPIE6OUT, GPIE6, GPIE6_DESC); +SIG_EXPR_DECL(GPIE6OUT, GPIE, GPIE_DESC); +SIG_EXPR_LIST_DECL_DUAL(GPIE6OUT, GPIE6, GPIE); +MS_PIN_DECL(B19, GPIOE7, RXD3, GPIE6OUT); +FUNC_GROUP_DECL(RXD3, B19); + +FUNC_GROUP_DECL(GPIE6, A20, B19); + +#define LPCHC_DESC SIG_DESC_IP_SET(ASPEED_IP_LPC, LHCR0, 0) +#define LPCPLUS_DESC SIG_DESC_SET(SCU90, 30) + +#define J19 40 +SIG_EXPR_DECL(LHAD0, LPCHC, LPCHC_DESC); +SIG_EXPR_DECL(LHAD0, LPCPLUS, LPCPLUS_DESC); +SIG_EXPR_LIST_DECL_DUAL(LHAD0, LPCHC, LPCPLUS); +SIG_EXPR_LIST_DECL_SINGLE(NCTS4, NCTS4, SIG_DESC_SET(SCU80, 24)); +MS_PIN_DECL(J19, GPIOF0, LHAD0, NCTS4); +FUNC_GROUP_DECL(NCTS4, J19); + +#define J18 41 +SIG_EXPR_DECL(LHAD1, LPCHC, LPCHC_DESC); +SIG_EXPR_DECL(LHAD1, LPCPLUS, LPCPLUS_DESC); +SIG_EXPR_LIST_DECL_DUAL(LHAD1, LPCHC, LPCPLUS); +SIG_EXPR_LIST_DECL_SINGLE(NDCD4, NDCD4, SIG_DESC_SET(SCU80, 25)); +MS_PIN_DECL(J18, GPIOF1, LHAD1, NDCD4); +FUNC_GROUP_DECL(NDCD4, J18); + +#define B22 42 +SIG_EXPR_DECL(LHAD2, LPCHC, LPCHC_DESC); +SIG_EXPR_DECL(LHAD2, LPCPLUS, LPCPLUS_DESC); +SIG_EXPR_LIST_DECL_DUAL(LHAD2, LPCHC, LPCPLUS); +SIG_EXPR_LIST_DECL_SINGLE(NDSR4, NDSR4, SIG_DESC_SET(SCU80, 26)); +MS_PIN_DECL(B22, GPIOF2, LHAD2, NDSR4); +FUNC_GROUP_DECL(NDSR4, B22); + +#define B21 43 +SIG_EXPR_DECL(LHAD3, LPCHC, LPCHC_DESC); +SIG_EXPR_DECL(LHAD3, LPCPLUS, LPCPLUS_DESC); +SIG_EXPR_LIST_DECL_DUAL(LHAD3, LPCHC, LPCPLUS); +SIG_EXPR_LIST_DECL_SINGLE(NRI4, NRI4, SIG_DESC_SET(SCU80, 27)); +MS_PIN_DECL(B21, GPIOF3, LHAD3, NRI4); +FUNC_GROUP_DECL(NRI4, B21); + +#define A21 44 +SIG_EXPR_DECL(LHCLK, LPCHC, LPCHC_DESC); +SIG_EXPR_DECL(LHCLK, LPCPLUS, LPCPLUS_DESC); +SIG_EXPR_LIST_DECL_DUAL(LHCLK, LPCHC, LPCPLUS); +SIG_EXPR_LIST_DECL_SINGLE(NDTR4, NDTR4, SIG_DESC_SET(SCU80, 28)); +MS_PIN_DECL(A21, GPIOF4, LHCLK, NDTR4); +FUNC_GROUP_DECL(NDTR4, A21); + +#define H19 45 +SIG_EXPR_DECL(LHFRAME, LPCHC, LPCHC_DESC); +SIG_EXPR_DECL(LHFRAME, LPCPLUS, LPCPLUS_DESC); +SIG_EXPR_LIST_DECL_DUAL(LHFRAME, LPCHC, LPCPLUS); +SIG_EXPR_LIST_DECL_SINGLE(NRTS4, NRTS4, SIG_DESC_SET(SCU80, 29)); +MS_PIN_DECL(H19, GPIOF5, LHFRAME, NRTS4); +FUNC_GROUP_DECL(NRTS4, H19); + +#define G17 46 +SIG_EXPR_LIST_DECL_SINGLE(LHSIRQ, LPCHC, LPCHC_DESC); +SIG_EXPR_LIST_DECL_SINGLE(TXD4, TXD4, SIG_DESC_SET(SCU80, 30)); +MS_PIN_DECL(G17, GPIOF6, LHSIRQ, TXD4); +FUNC_GROUP_DECL(TXD4, G17); + +#define H18 47 +SIG_EXPR_DECL(LHRST, LPCHC, LPCHC_DESC); +SIG_EXPR_DECL(LHRST, LPCPLUS, LPCPLUS_DESC); +SIG_EXPR_LIST_DECL_DUAL(LHRST, LPCHC, LPCPLUS); +SIG_EXPR_LIST_DECL_SINGLE(RXD4, RXD4, SIG_DESC_SET(SCU80, 31)); +MS_PIN_DECL(H18, GPIOF7, LHRST, RXD4); +FUNC_GROUP_DECL(RXD4, H18); + +FUNC_GROUP_DECL(LPCHC, J19, J18, B22, B21, A21, H19, G17, H18); +FUNC_GROUP_DECL(LPCPLUS, J19, J18, B22, B21, A21, H19, H18); + +#define A19 48 +SIG_EXPR_LIST_DECL_SINGLE(SGPS1CK, SGPS1, COND1, SIG_DESC_SET(SCU84, 0)); +SS_PIN_DECL(A19, GPIOG0, SGPS1CK); + +#define E19 49 +SIG_EXPR_LIST_DECL_SINGLE(SGPS1LD, SGPS1, COND1, SIG_DESC_SET(SCU84, 1)); +SS_PIN_DECL(E19, GPIOG1, SGPS1LD); + +#define C19 50 +SIG_EXPR_LIST_DECL_SINGLE(SGPS1I0, SGPS1, COND1, SIG_DESC_SET(SCU84, 2)); +SS_PIN_DECL(C19, GPIOG2, SGPS1I0); + +#define E16 51 +SIG_EXPR_LIST_DECL_SINGLE(SGPS1I1, SGPS1, COND1, SIG_DESC_SET(SCU84, 3)); +SS_PIN_DECL(E16, GPIOG3, SGPS1I1); + +FUNC_GROUP_DECL(SGPS1, A19, E19, C19, E16); + +#define SGPS2_DESC SIG_DESC_SET(SCU94, 12) + +#define E17 52 +SIG_EXPR_LIST_DECL_SINGLE(SGPS2CK, SGPS2, COND1, SGPS2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(SALT1, SALT1, COND1, SIG_DESC_SET(SCU84, 4)); +MS_PIN_DECL(E17, GPIOG4, SGPS2CK, SALT1); +FUNC_GROUP_DECL(SALT1, E17); + +#define D16 53 +SIG_EXPR_LIST_DECL_SINGLE(SGPS2LD, SGPS2, COND1, SGPS2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(SALT2, SALT2, COND1, SIG_DESC_SET(SCU84, 5)); +MS_PIN_DECL(D16, GPIOG5, SGPS2LD, SALT2); +FUNC_GROUP_DECL(SALT2, D16); + +#define D15 54 +SIG_EXPR_LIST_DECL_SINGLE(SGPS2I0, SGPS2, COND1, SGPS2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(SALT3, SALT3, COND1, SIG_DESC_SET(SCU84, 6)); +MS_PIN_DECL(D15, GPIOG6, SGPS2I0, SALT3); +FUNC_GROUP_DECL(SALT3, D15); + +#define E14 55 +SIG_EXPR_LIST_DECL_SINGLE(SGPS2I1, SGPS2, COND1, SGPS2_DESC); +SIG_EXPR_LIST_DECL_SINGLE(SALT4, SALT4, COND1, SIG_DESC_SET(SCU84, 7)); +MS_PIN_DECL(E14, GPIOG7, SGPS2I1, SALT4); +FUNC_GROUP_DECL(SALT4, E14); + +FUNC_GROUP_DECL(SGPS2, E17, D16, D15, E14); + +#define UART6_DESC SIG_DESC_SET(SCU90, 7) + +#define A18 56 +SIG_EXPR_LIST_DECL_SINGLE(DASHA18, DASHA18, COND1, SIG_DESC_SET(SCU94, 5)); +SIG_EXPR_LIST_DECL_SINGLE(NCTS6, UART6, COND1, UART6_DESC); +MS_PIN_DECL(A18, GPIOH0, DASHA18, NCTS6); + +#define B18 57 +SIG_EXPR_LIST_DECL_SINGLE(DASHB18, DASHB18, COND1, SIG_DESC_SET(SCU94, 5)); +SIG_EXPR_LIST_DECL_SINGLE(NDCD6, UART6, COND1, UART6_DESC); +MS_PIN_DECL(B18, GPIOH1, DASHB18, NDCD6); + +#define D17 58 +SIG_EXPR_LIST_DECL_SINGLE(DASHD17, DASHD17, COND1, SIG_DESC_SET(SCU94, 6)); +SIG_EXPR_LIST_DECL_SINGLE(NDSR6, UART6, COND1, UART6_DESC); +MS_PIN_DECL(D17, GPIOH2, DASHD17, NDSR6); + +#define C17 59 +SIG_EXPR_LIST_DECL_SINGLE(DASHC17, DASHC17, COND1, SIG_DESC_SET(SCU94, 6)); +SIG_EXPR_LIST_DECL_SINGLE(NRI6, UART6, COND1, UART6_DESC); +MS_PIN_DECL(C17, GPIOH3, DASHC17, NRI6); + +#define A17 60 +SIG_EXPR_LIST_DECL_SINGLE(DASHA17, DASHA17, COND1, SIG_DESC_SET(SCU94, 7)); +SIG_EXPR_LIST_DECL_SINGLE(NDTR6, UART6, COND1, UART6_DESC); +MS_PIN_DECL(A17, GPIOH4, DASHA17, NDTR6); + +#define B17 61 +SIG_EXPR_LIST_DECL_SINGLE(DASHB17, DASHB17, COND1, SIG_DESC_SET(SCU94, 7)); +SIG_EXPR_LIST_DECL_SINGLE(NRTS6, UART6, COND1, UART6_DESC); +MS_PIN_DECL(B17, GPIOH5, DASHB17, NRTS6); + +#define A16 62 +SIG_EXPR_LIST_DECL_SINGLE(TXD6, UART6, COND1, UART6_DESC); +SS_PIN_DECL(A16, GPIOH6, TXD6); + +#define D18 63 +SIG_EXPR_LIST_DECL_SINGLE(RXD6, UART6, COND1, UART6_DESC); +SS_PIN_DECL(D18, GPIOH7, RXD6); + +FUNC_GROUP_DECL(UART6, A18, B18, D17, C17, A17, B17, A16, D18); + #define SPI1_DESC \ { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 1, 0 } #define SPI1DEBUG_DESC \ @@ -281,6 +577,30 @@ SS_PIN_DECL(N3, GPIOJ2, SGPMO); SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11)); SS_PIN_DECL(N4, GPIOJ3, SGPMI); +#define N5 76 +SIG_EXPR_LIST_DECL_SINGLE(VGAHS, VGAHS, SIG_DESC_SET(SCU84, 12)); +SIG_EXPR_LIST_DECL_SINGLE(DASHN5, DASHN5, SIG_DESC_SET(SCU94, 8)); +MS_PIN_DECL(N5, GPIOJ4, VGAHS, DASHN5); +FUNC_GROUP_DECL(VGAHS, N5); + +#define R4 77 +SIG_EXPR_LIST_DECL_SINGLE(VGAVS, VGAVS, SIG_DESC_SET(SCU84, 13)); +SIG_EXPR_LIST_DECL_SINGLE(DASHR4, DASHR4, SIG_DESC_SET(SCU94, 8)); +MS_PIN_DECL(R4, GPIOJ5, VGAVS, DASHR4); +FUNC_GROUP_DECL(VGAVS, R4); + +#define R3 78 +SIG_EXPR_LIST_DECL_SINGLE(DDCCLK, DDCCLK, SIG_DESC_SET(SCU84, 14)); +SIG_EXPR_LIST_DECL_SINGLE(DASHR3, DASHR3, SIG_DESC_SET(SCU94, 9)); +MS_PIN_DECL(R3, GPIOJ6, DDCCLK, DASHR3); +FUNC_GROUP_DECL(DDCCLK, R3); + +#define T3 79 +SIG_EXPR_LIST_DECL_SINGLE(DDCDAT, DDCDAT, SIG_DESC_SET(SCU84, 15)); +SIG_EXPR_LIST_DECL_SINGLE(DASHT3, DASHT3, SIG_DESC_SET(SCU94, 9)); +MS_PIN_DECL(T3, GPIOJ7, DDCDAT, DASHT3); +FUNC_GROUP_DECL(DDCDAT, T3); + #define I2C5_DESC SIG_DESC_SET(SCU90, 18) #define L3 80 @@ -329,11 +649,119 @@ SS_PIN_DECL(R1, GPIOK7, SDA8); FUNC_GROUP_DECL(I2C8, P2, R1); +#define T2 88 +SSSF_PIN_DECL(T2, GPIOL0, NCTS1, SIG_DESC_SET(SCU84, 16)); + #define VPIOFF0_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 0, 0 } #define VPIOFF1_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 1, 0 } #define VPI24_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 2, 0 } #define VPIRSVD_DESC { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 3, 0 } +#define VPI_24_RSVD_DESC SIG_DESC_SET(SCU90, 5) +#define T1 89 +#define T1_DESC SIG_DESC_SET(SCU84, 17) +SIG_EXPR_LIST_DECL_SINGLE(VPIDE, VPI24, VPI_24_RSVD_DESC, T1_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NDCD1, NDCD1, T1_DESC, COND2); +MS_PIN_DECL(T1, GPIOL1, VPIDE, NDCD1); +FUNC_GROUP_DECL(NDCD1, T1); + +#define U1 90 +#define U1_DESC SIG_DESC_SET(SCU84, 18) +SIG_EXPR_LIST_DECL_SINGLE(DASHU1, VPI24, VPI_24_RSVD_DESC, U1_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NDSR1, NDSR1, U1_DESC); +MS_PIN_DECL(U1, GPIOL2, DASHU1, NDSR1); +FUNC_GROUP_DECL(NDSR1, U1); + +#define U2 91 +#define U2_DESC SIG_DESC_SET(SCU84, 19) +SIG_EXPR_LIST_DECL_SINGLE(VPIHS, VPI24, VPI_24_RSVD_DESC, U2_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NRI1, NRI1, U2_DESC, COND2); +MS_PIN_DECL(U2, GPIOL3, VPIHS, NRI1); +FUNC_GROUP_DECL(NRI1, U2); + +#define P4 92 +#define P4_DESC SIG_DESC_SET(SCU84, 20) +SIG_EXPR_LIST_DECL_SINGLE(VPIVS, VPI24, VPI_24_RSVD_DESC, P4_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NDTR1, NDTR1, P4_DESC, COND2); +MS_PIN_DECL(P4, GPIOL4, VPIVS, NDTR1); +FUNC_GROUP_DECL(NDTR1, P4); + +#define P3 93 +#define P3_DESC SIG_DESC_SET(SCU84, 21) +SIG_EXPR_LIST_DECL_SINGLE(VPICLK, VPI24, VPI_24_RSVD_DESC, P3_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NRTS1, NRTS1, P3_DESC, COND2); +MS_PIN_DECL(P3, GPIOL5, VPICLK, NRTS1); +FUNC_GROUP_DECL(NRTS1, P3); + +#define V1 94 +#define V1_DESC SIG_DESC_SET(SCU84, 22) +SIG_EXPR_LIST_DECL_SINGLE(DASHV1, DASHV1, VPIRSVD_DESC, V1_DESC); +SIG_EXPR_LIST_DECL_SINGLE(TXD1, TXD1, V1_DESC, COND2); +MS_PIN_DECL(V1, GPIOL6, DASHV1, TXD1); +FUNC_GROUP_DECL(TXD1, V1); + +#define W1 95 +#define W1_DESC SIG_DESC_SET(SCU84, 23) +SIG_EXPR_LIST_DECL_SINGLE(DASHW1, DASHW1, VPIRSVD_DESC, W1_DESC); +SIG_EXPR_LIST_DECL_SINGLE(RXD1, RXD1, W1_DESC, COND2); +MS_PIN_DECL(W1, GPIOL7, DASHW1, RXD1); +FUNC_GROUP_DECL(RXD1, W1); + +#define Y1 96 +#define Y1_DESC SIG_DESC_SET(SCU84, 24) +SIG_EXPR_LIST_DECL_SINGLE(VPIB2, VPI24, VPI_24_RSVD_DESC, Y1_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NCTS2, NCTS2, Y1_DESC, COND2); +MS_PIN_DECL(Y1, GPIOM0, VPIB2, NCTS2); +FUNC_GROUP_DECL(NCTS2, Y1); + +#define AB2 97 +#define AB2_DESC SIG_DESC_SET(SCU84, 25) +SIG_EXPR_LIST_DECL_SINGLE(VPIB3, VPI24, VPI_24_RSVD_DESC, AB2_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NDCD2, NDCD2, AB2_DESC, COND2); +MS_PIN_DECL(AB2, GPIOM1, VPIB3, NDCD2); +FUNC_GROUP_DECL(NDCD2, AB2); + +#define AA1 98 +#define AA1_DESC SIG_DESC_SET(SCU84, 26) +SIG_EXPR_LIST_DECL_SINGLE(VPIB4, VPI24, VPI_24_RSVD_DESC, AA1_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NDSR2, NDSR2, AA1_DESC, COND2); +MS_PIN_DECL(AA1, GPIOM2, VPIB4, NDSR2); +FUNC_GROUP_DECL(NDSR2, AA1); + +#define Y2 99 +#define Y2_DESC SIG_DESC_SET(SCU84, 27) +SIG_EXPR_LIST_DECL_SINGLE(VPIB5, VPI24, VPI_24_RSVD_DESC, Y2_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NRI2, NRI2, Y2_DESC, COND2); +MS_PIN_DECL(Y2, GPIOM3, VPIB5, NRI2); +FUNC_GROUP_DECL(NRI2, Y2); + +#define AA2 100 +#define AA2_DESC SIG_DESC_SET(SCU84, 28) +SIG_EXPR_LIST_DECL_SINGLE(VPIB6, VPI24, VPI_24_RSVD_DESC, AA2_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NDTR2, NDTR2, AA2_DESC, COND2); +MS_PIN_DECL(AA2, GPIOM4, VPIB6, NDTR2); +FUNC_GROUP_DECL(NDTR2, AA2); + +#define P5 101 +#define P5_DESC SIG_DESC_SET(SCU84, 29) +SIG_EXPR_LIST_DECL_SINGLE(VPIB7, VPI24, VPI_24_RSVD_DESC, P5_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(NRTS2, NRTS2, P5_DESC, COND2); +MS_PIN_DECL(P5, GPIOM5, VPIB7, NRTS2); +FUNC_GROUP_DECL(NRTS2, P5); + +#define R5 102 +#define R5_DESC SIG_DESC_SET(SCU84, 30) +SIG_EXPR_LIST_DECL_SINGLE(VPIB8, VPI24, VPI_24_RSVD_DESC, R5_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(TXD2, TXD2, R5_DESC, COND2); +MS_PIN_DECL(R5, GPIOM6, VPIB8, TXD2); +FUNC_GROUP_DECL(TXD2, R5); + +#define T5 103 +#define T5_DESC SIG_DESC_SET(SCU84, 31) +SIG_EXPR_LIST_DECL_SINGLE(VPIB9, VPI24, VPI_24_RSVD_DESC, T5_DESC, COND2); +SIG_EXPR_LIST_DECL_SINGLE(RXD2, RXD2, T5_DESC, COND2); +MS_PIN_DECL(T5, GPIOM7, VPIB9, RXD2); +FUNC_GROUP_DECL(RXD2, T5); #define V2 104 #define V2_DESC SIG_DESC_SET(SCU88, 0) @@ -399,9 +827,88 @@ SIG_EXPR_LIST_DECL_SINGLE(PWM7, PWM7, T4_DESC, COND2); MS_PIN_DECL(T4, GPION7, VPIG7, PWM7); FUNC_GROUP_DECL(PWM7, T4); +#define U5 112 +SIG_EXPR_LIST_DECL_SINGLE(VPIG8, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 8), + COND2); +SS_PIN_DECL(U5, GPIOO0, VPIG8); + +#define U4 113 +SIG_EXPR_LIST_DECL_SINGLE(VPIG9, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 9), + COND2); +SS_PIN_DECL(U4, GPIOO1, VPIG9); + +#define V5 114 +SIG_EXPR_LIST_DECL_SINGLE(DASHV5, DASHV5, VPI_24_RSVD_DESC, + SIG_DESC_SET(SCU88, 10)); +SS_PIN_DECL(V5, GPIOO2, DASHV5); + +#define AB4 115 +SIG_EXPR_LIST_DECL_SINGLE(DASHAB4, DASHAB4, VPI_24_RSVD_DESC, + SIG_DESC_SET(SCU88, 11)); +SS_PIN_DECL(AB4, GPIOO3, DASHAB4); + +#define AB3 116 +SIG_EXPR_LIST_DECL_SINGLE(VPIR2, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 12), + COND2); +SS_PIN_DECL(AB3, GPIOO4, VPIR2); + +#define Y4 117 +SIG_EXPR_LIST_DECL_SINGLE(VPIR3, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 13), + COND2); +SS_PIN_DECL(Y4, GPIOO5, VPIR3); + +#define AA4 118 +SIG_EXPR_LIST_DECL_SINGLE(VPIR4, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 14), + COND2); +SS_PIN_DECL(AA4, GPIOO6, VPIR4); + +#define W4 119 +SIG_EXPR_LIST_DECL_SINGLE(VPIR5, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 15), + COND2); +SS_PIN_DECL(W4, GPIOO7, VPIR5); + +#define V4 120 +SIG_EXPR_LIST_DECL_SINGLE(VPIR6, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 16), + COND2); +SS_PIN_DECL(V4, GPIOP0, VPIR6); + +#define W5 121 +SIG_EXPR_LIST_DECL_SINGLE(VPIR7, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 17), + COND2); +SS_PIN_DECL(W5, GPIOP1, VPIR7); + +#define AA5 122 +SIG_EXPR_LIST_DECL_SINGLE(VPIR8, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 18), + COND2); +SS_PIN_DECL(AA5, GPIOP2, VPIR8); + +#define AB5 123 +SIG_EXPR_LIST_DECL_SINGLE(VPIR9, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 19), + COND2); +SS_PIN_DECL(AB5, GPIOP3, VPIR9); + +FUNC_GROUP_DECL(VPI24, T1, U2, P4, P3, Y1, AB2, AA1, Y2, AA2, P5, R5, T5, V3, + U3, W3, AA3, Y3, T4, U5, U4, AB3, Y4, AA4, W4, V4, W5, AA5, + AB5); + +#define Y6 124 +SIG_EXPR_LIST_DECL_SINGLE(DASHY6, DASHY6, SIG_DESC_SET(SCU90, 28), + SIG_DESC_SET(SCU88, 20)); +SS_PIN_DECL(Y6, GPIOP4, DASHY6); + +#define Y5 125 +SIG_EXPR_LIST_DECL_SINGLE(DASHY5, DASHY5, SIG_DESC_SET(SCU90, 28), + SIG_DESC_SET(SCU88, 21)); +SS_PIN_DECL(Y5, GPIOP5, DASHY5); + +#define W6 126 +SIG_EXPR_LIST_DECL_SINGLE(DASHW6, DASHW6, SIG_DESC_SET(SCU90, 28), + SIG_DESC_SET(SCU88, 22)); +SS_PIN_DECL(W6, GPIOP6, DASHW6); + #define V6 127 SIG_EXPR_LIST_DECL_SINGLE(DASHV6, DASHV6, SIG_DESC_SET(SCU90, 28), - SIG_DESC_SET(SCU88, 23)); + SIG_DESC_SET(SCU88, 23)); SS_PIN_DECL(V6, GPIOP7, DASHV6); #define I2C3_DESC SIG_DESC_SET(SCU90, 16) @@ -446,6 +953,24 @@ SSSF_PIN_DECL(B10, GPIOQ6, OSCCLK, SIG_DESC_SET(SCU2C, 1)); #define N20 135 SSSF_PIN_DECL(N20, GPIOQ7, PEWAKE, SIG_DESC_SET(SCU2C, 29)); +#define AA19 136 +SSSF_PIN_DECL(AA19, GPIOR0, FWSPICS1, SIG_DESC_SET(SCU88, 24), COND2); + +#define T19 137 +SSSF_PIN_DECL(T19, GPIOR1, FWSPICS2, SIG_DESC_SET(SCU88, 25), COND2); + +#define T17 138 +SSSF_PIN_DECL(T17, GPIOR2, SPI2CS0, SIG_DESC_SET(SCU88, 26), COND2); + +#define Y19 139 +SSSF_PIN_DECL(Y19, GPIOR3, SPI2CK, SIG_DESC_SET(SCU88, 27), COND2); + +#define W19 140 +SSSF_PIN_DECL(W19, GPIOR4, SPI2MOSI, SIG_DESC_SET(SCU88, 28), COND2); + +#define V19 141 +SSSF_PIN_DECL(V19, GPIOR5, SPI2MISO, SIG_DESC_SET(SCU88, 29), COND2); + #define D8 142 SIG_EXPR_LIST_DECL_SINGLE(MDC1, MDIO1, SIG_DESC_SET(SCU88, 30)); SS_PIN_DECL(D8, GPIOR6, MDC1); @@ -456,6 +981,93 @@ SS_PIN_DECL(E10, GPIOR7, MDIO1); FUNC_GROUP_DECL(MDIO1, D8, E10); +#define VPOOFF0_DESC { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 0, 0 } +#define VPO_DESC { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 1, 0 } +#define VPOOFF1_DESC { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 2, 0 } +#define VPOOFF2_DESC { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 3, 0 } + +#define CRT_DVO_EN_DESC SIG_DESC_IP_SET(ASPEED_IP_GFX, GFX064, 7) + +#define V20 144 +#define V20_DESC SIG_DESC_SET(SCU8C, 0) +SIG_EXPR_DECL(VPOB2, VPO, V20_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB2, VPOOFF1, V20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB2, VPOOFF2, V20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOB2, SIG_EXPR_PTR(VPOB2, VPO), + SIG_EXPR_PTR(VPOB2, VPOOFF1), SIG_EXPR_PTR(VPOB2, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SPI2CS1, SPI2CS1, V20_DESC); +MS_PIN_DECL(V20, GPIOS0, VPOB2, SPI2CS1); +FUNC_GROUP_DECL(SPI2CS1, V20); + +#define U19 145 +#define U19_DESC SIG_DESC_SET(SCU8C, 1) +SIG_EXPR_DECL(VPOB3, VPO, U19_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB3, VPOOFF1, U19_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB3, VPOOFF2, U19_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOB3, SIG_EXPR_PTR(VPOB3, VPO), + SIG_EXPR_PTR(VPOB3, VPOOFF1), SIG_EXPR_PTR(VPOB3, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(BMCINT, BMCINT, U19_DESC); +MS_PIN_DECL(U19, GPIOS1, VPOB3, BMCINT); +FUNC_GROUP_DECL(BMCINT, U19); + +#define R18 146 +#define R18_DESC SIG_DESC_SET(SCU8C, 2) +SIG_EXPR_DECL(VPOB4, VPO, R18_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB4, VPOOFF1, R18_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB4, VPOOFF2, R18_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOB4, SIG_EXPR_PTR(VPOB4, VPO), + SIG_EXPR_PTR(VPOB4, VPOOFF1), SIG_EXPR_PTR(VPOB4, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT5, SALT5, R18_DESC); +MS_PIN_DECL(R18, GPIOS2, VPOB4, SALT5); +FUNC_GROUP_DECL(SALT5, R18); + +#define P18 147 +#define P18_DESC SIG_DESC_SET(SCU8C, 3) +SIG_EXPR_DECL(VPOB5, VPO, P18_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB5, VPOOFF1, P18_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB5, VPOOFF2, P18_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOB5, SIG_EXPR_PTR(VPOB5, VPO), + SIG_EXPR_PTR(VPOB5, VPOOFF1), SIG_EXPR_PTR(VPOB5, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT6, SALT6, P18_DESC); +MS_PIN_DECL(P18, GPIOS3, VPOB5, SALT6); +FUNC_GROUP_DECL(SALT6, P18); + +#define R19 148 +#define R19_DESC SIG_DESC_SET(SCU8C, 4) +SIG_EXPR_DECL(VPOB6, VPO, R19_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB6, VPOOFF1, R19_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB6, VPOOFF2, R19_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOB6, SIG_EXPR_PTR(VPOB6, VPO), + SIG_EXPR_PTR(VPOB6, VPOOFF1), SIG_EXPR_PTR(VPOB6, VPOOFF2)); +SS_PIN_DECL(R19, GPIOS4, VPOB6); + +#define W20 149 +#define W20_DESC SIG_DESC_SET(SCU8C, 5) +SIG_EXPR_DECL(VPOB7, VPO, W20_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB7, VPOOFF1, W20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB7, VPOOFF2, W20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOB7, SIG_EXPR_PTR(VPOB7, VPO), + SIG_EXPR_PTR(VPOB7, VPOOFF1), SIG_EXPR_PTR(VPOB7, VPOOFF2)); +SS_PIN_DECL(W20, GPIOS5, VPOB7); + +#define U20 150 +#define U20_DESC SIG_DESC_SET(SCU8C, 6) +SIG_EXPR_DECL(VPOB8, VPO, U20_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB8, VPOOFF1, U20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB8, VPOOFF2, U20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOB8, SIG_EXPR_PTR(VPOB8, VPO), + SIG_EXPR_PTR(VPOB8, VPOOFF1), SIG_EXPR_PTR(VPOB8, VPOOFF2)); +SS_PIN_DECL(U20, GPIOS6, VPOB8); + +#define AA20 151 +#define AA20_DESC SIG_DESC_SET(SCU8C, 7) +SIG_EXPR_DECL(VPOB9, VPO, AA20_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB9, VPOOFF1, AA20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOB9, VPOOFF2, AA20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOB9, SIG_EXPR_PTR(VPOB9, VPO), + SIG_EXPR_PTR(VPOB9, VPOOFF1), SIG_EXPR_PTR(VPOB9, VPOOFF2)); +SS_PIN_DECL(AA20, GPIOS7, VPOB9); + /* RGMII1/RMII1 */ #define RMII1_DESC SIG_DESC_BIT(HW_STRAP1, 6, 0) @@ -637,6 +1249,481 @@ MS_PIN_DECL_(E6, SIG_EXPR_LIST_PTR(GPIOV7), SIG_EXPR_LIST_PTR(RMII2RXER), FUNC_GROUP_DECL(RGMII2, B2, B1, A2, B3, D5, D4, C2, C1, C3, D1, D2, E6); FUNC_GROUP_DECL(RMII2, B2, B1, A2, B3, C2, C3, D1, D2, E6); +#define F4 176 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW0, GPIOW0, SIG_DESC_SET(SCUA0, 24)); +SIG_EXPR_LIST_DECL_SINGLE(ADC0, ADC0); +MS_PIN_DECL_(F4, SIG_EXPR_LIST_PTR(GPIOW0), SIG_EXPR_LIST_PTR(ADC0)); +FUNC_GROUP_DECL(ADC0, F4); + +#define F5 177 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW1, GPIOW1, SIG_DESC_SET(SCUA0, 25)); +SIG_EXPR_LIST_DECL_SINGLE(ADC1, ADC1); +MS_PIN_DECL_(F5, SIG_EXPR_LIST_PTR(GPIOW1), SIG_EXPR_LIST_PTR(ADC1)); +FUNC_GROUP_DECL(ADC1, F5); + +#define E2 178 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW2, GPIOW2, SIG_DESC_SET(SCUA0, 26)); +SIG_EXPR_LIST_DECL_SINGLE(ADC2, ADC2); +MS_PIN_DECL_(E2, SIG_EXPR_LIST_PTR(GPIOW2), SIG_EXPR_LIST_PTR(ADC2)); +FUNC_GROUP_DECL(ADC2, E2); + +#define E1 179 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW3, GPIOW3, SIG_DESC_SET(SCUA0, 27)); +SIG_EXPR_LIST_DECL_SINGLE(ADC3, ADC3); +MS_PIN_DECL_(E1, SIG_EXPR_LIST_PTR(GPIOW3), SIG_EXPR_LIST_PTR(ADC3)); +FUNC_GROUP_DECL(ADC3, E1); + +#define F3 180 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW4, GPIOW4, SIG_DESC_SET(SCUA0, 28)); +SIG_EXPR_LIST_DECL_SINGLE(ADC4, ADC4); +MS_PIN_DECL_(F3, SIG_EXPR_LIST_PTR(GPIOW4), SIG_EXPR_LIST_PTR(ADC4)); +FUNC_GROUP_DECL(ADC4, F3); + +#define E3 181 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW5, GPIOW5, SIG_DESC_SET(SCUA0, 29)); +SIG_EXPR_LIST_DECL_SINGLE(ADC5, ADC5); +MS_PIN_DECL_(E3, SIG_EXPR_LIST_PTR(GPIOW5), SIG_EXPR_LIST_PTR(ADC5)); +FUNC_GROUP_DECL(ADC5, E3); + +#define G5 182 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW6, GPIOW6, SIG_DESC_SET(SCUA0, 30)); +SIG_EXPR_LIST_DECL_SINGLE(ADC6, ADC6); +MS_PIN_DECL_(G5, SIG_EXPR_LIST_PTR(GPIOW6), SIG_EXPR_LIST_PTR(ADC6)); +FUNC_GROUP_DECL(ADC6, G5); + +#define G4 183 +SIG_EXPR_LIST_DECL_SINGLE(GPIOW7, GPIOW7, SIG_DESC_SET(SCUA0, 31)); +SIG_EXPR_LIST_DECL_SINGLE(ADC7, ADC7); +MS_PIN_DECL_(G4, SIG_EXPR_LIST_PTR(GPIOW7), SIG_EXPR_LIST_PTR(ADC7)); +FUNC_GROUP_DECL(ADC7, G4); + +#define F2 184 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX0, GPIOX0, SIG_DESC_SET(SCUA4, 0)); +SIG_EXPR_LIST_DECL_SINGLE(ADC8, ADC8); +MS_PIN_DECL_(F2, SIG_EXPR_LIST_PTR(GPIOX0), SIG_EXPR_LIST_PTR(ADC8)); +FUNC_GROUP_DECL(ADC8, F2); + +#define G3 185 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX1, GPIOX1, SIG_DESC_SET(SCUA4, 1)); +SIG_EXPR_LIST_DECL_SINGLE(ADC9, ADC9); +MS_PIN_DECL_(G3, SIG_EXPR_LIST_PTR(GPIOX1), SIG_EXPR_LIST_PTR(ADC9)); +FUNC_GROUP_DECL(ADC9, G3); + +#define G2 186 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX2, GPIOX2, SIG_DESC_SET(SCUA4, 2)); +SIG_EXPR_LIST_DECL_SINGLE(ADC10, ADC10); +MS_PIN_DECL_(G2, SIG_EXPR_LIST_PTR(GPIOX2), SIG_EXPR_LIST_PTR(ADC10)); +FUNC_GROUP_DECL(ADC10, G2); + +#define F1 187 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX3, GPIOX3, SIG_DESC_SET(SCUA4, 3)); +SIG_EXPR_LIST_DECL_SINGLE(ADC11, ADC11); +MS_PIN_DECL_(F1, SIG_EXPR_LIST_PTR(GPIOX3), SIG_EXPR_LIST_PTR(ADC11)); +FUNC_GROUP_DECL(ADC11, F1); + +#define H5 188 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX4, GPIOX4, SIG_DESC_SET(SCUA4, 4)); +SIG_EXPR_LIST_DECL_SINGLE(ADC12, ADC12); +MS_PIN_DECL_(H5, SIG_EXPR_LIST_PTR(GPIOX4), SIG_EXPR_LIST_PTR(ADC12)); +FUNC_GROUP_DECL(ADC12, H5); + +#define G1 189 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX5, GPIOX5, SIG_DESC_SET(SCUA4, 5)); +SIG_EXPR_LIST_DECL_SINGLE(ADC13, ADC13); +MS_PIN_DECL_(G1, SIG_EXPR_LIST_PTR(GPIOX5), SIG_EXPR_LIST_PTR(ADC13)); +FUNC_GROUP_DECL(ADC13, G1); + +#define H3 190 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX6, GPIOX6, SIG_DESC_SET(SCUA4, 6)); +SIG_EXPR_LIST_DECL_SINGLE(ADC14, ADC14); +MS_PIN_DECL_(H3, SIG_EXPR_LIST_PTR(GPIOX6), SIG_EXPR_LIST_PTR(ADC14)); +FUNC_GROUP_DECL(ADC14, H3); + +#define H4 191 +SIG_EXPR_LIST_DECL_SINGLE(GPIOX7, GPIOX7, SIG_DESC_SET(SCUA4, 7)); +SIG_EXPR_LIST_DECL_SINGLE(ADC15, ADC15); +MS_PIN_DECL_(H4, SIG_EXPR_LIST_PTR(GPIOX7), SIG_EXPR_LIST_PTR(ADC15)); +FUNC_GROUP_DECL(ADC15, H4); + +#define ACPI_DESC SIG_DESC_SET(HW_STRAP1, 19) + +#define R22 192 +SIG_EXPR_DECL(SIOS3, SIOS3, SIG_DESC_SET(SCUA4, 8)); +SIG_EXPR_DECL(SIOS3, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOS3, SIOS3, ACPI); +SIG_EXPR_LIST_DECL_SINGLE(DASHR22, DASHR22, SIG_DESC_SET(SCU94, 10)); +MS_PIN_DECL(R22, GPIOY0, SIOS3, DASHR22); +FUNC_GROUP_DECL(SIOS3, R22); + +#define R21 193 +SIG_EXPR_DECL(SIOS5, SIOS5, SIG_DESC_SET(SCUA4, 9)); +SIG_EXPR_DECL(SIOS5, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOS5, SIOS5, ACPI); +SIG_EXPR_LIST_DECL_SINGLE(DASHR21, DASHR21, SIG_DESC_SET(SCU94, 10)); +MS_PIN_DECL(R21, GPIOY1, SIOS5, DASHR21); +FUNC_GROUP_DECL(SIOS5, R21); + +#define P22 194 +SIG_EXPR_DECL(SIOPWREQ, SIOPWREQ, SIG_DESC_SET(SCUA4, 10)); +SIG_EXPR_DECL(SIOPWREQ, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOPWREQ, SIOPWREQ, ACPI); +SIG_EXPR_LIST_DECL_SINGLE(DASHP22, DASHP22, SIG_DESC_SET(SCU94, 11)); +MS_PIN_DECL(P22, GPIOY2, SIOPWREQ, DASHP22); +FUNC_GROUP_DECL(SIOPWREQ, P22); + +#define P21 195 +SIG_EXPR_DECL(SIOONCTRL, SIOONCTRL, SIG_DESC_SET(SCUA4, 11)); +SIG_EXPR_DECL(SIOONCTRL, ACPI, ACPI_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOONCTRL, SIOONCTRL, ACPI); +SIG_EXPR_LIST_DECL_SINGLE(DASHP21, DASHP21, SIG_DESC_SET(SCU94, 11)); +MS_PIN_DECL(P21, GPIOY3, SIOONCTRL, DASHP21); +FUNC_GROUP_DECL(SIOONCTRL, P21); + +#define M18 196 +SSSF_PIN_DECL(M18, GPIOY4, SCL1, SIG_DESC_SET(SCUA4, 12)); + +#define M19 197 +SSSF_PIN_DECL(M19, GPIOY5, SDA1, SIG_DESC_SET(SCUA4, 13)); + +#define M20 198 +SSSF_PIN_DECL(M20, GPIOY6, SCL2, SIG_DESC_SET(SCUA4, 14)); + +#define P20 199 +SSSF_PIN_DECL(P20, GPIOY7, SDA2, SIG_DESC_SET(SCUA4, 15)); + +#define PNOR_DESC SIG_DESC_SET(SCU90, 31) + +#define Y20 200 +#define Y20_DESC SIG_DESC_SET(SCUA4, 16) +SIG_EXPR_DECL(VPOG2, VPO, Y20_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOG2, VPOOFF1, Y20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOG2, VPOOFF2, Y20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOG2, SIG_EXPR_PTR(VPOG2, VPO), + SIG_EXPR_PTR(VPOG2, VPOOFF1), SIG_EXPR_PTR(VPOG2, VPOOFF2)); +SIG_EXPR_DECL(SIOPBI, SIOPBI, Y20_DESC); +SIG_EXPR_DECL(SIOPBI, ACPI, Y20_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOPBI, SIOPBI, ACPI); +SIG_EXPR_LIST_DECL_SINGLE(NORA0, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOZ0, GPIOZ0); +MS_PIN_DECL_(Y20, SIG_EXPR_LIST_PTR(VPOG2), SIG_EXPR_LIST_PTR(SIOPBI), + SIG_EXPR_LIST_PTR(NORA0), SIG_EXPR_LIST_PTR(GPIOZ0)); +FUNC_GROUP_DECL(SIOPBI, Y20); + +#define AB20 201 +#define AB20_DESC SIG_DESC_SET(SCUA4, 17) +SIG_EXPR_DECL(VPOG3, VPO, AB20_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOG3, VPOOFF1, AB20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOG3, VPOOFF2, AB20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOG3, SIG_EXPR_PTR(VPOG3, VPO), + SIG_EXPR_PTR(VPOG3, VPOOFF1), SIG_EXPR_PTR(VPOG3, VPOOFF2)); +SIG_EXPR_DECL(SIOPWRGD, SIOPWRGD, AB20_DESC); +SIG_EXPR_DECL(SIOPWRGD, ACPI, AB20_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOPWRGD, SIOPWRGD, ACPI); +SIG_EXPR_LIST_DECL_SINGLE(NORA1, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOZ1, GPIOZ1); +MS_PIN_DECL_(AB20, SIG_EXPR_LIST_PTR(VPOG3), SIG_EXPR_LIST_PTR(SIOPWRGD), + SIG_EXPR_LIST_PTR(NORA1), SIG_EXPR_LIST_PTR(GPIOZ1)); +FUNC_GROUP_DECL(SIOPWRGD, AB20); + +#define AB21 202 +#define AB21_DESC SIG_DESC_SET(SCUA4, 18) +SIG_EXPR_DECL(VPOG4, VPO, AB21_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOG4, VPOOFF1, AB21_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOG4, VPOOFF2, AB21_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOG4, SIG_EXPR_PTR(VPOG4, VPO), + SIG_EXPR_PTR(VPOG4, VPOOFF1), SIG_EXPR_PTR(VPOG4, VPOOFF2)); +SIG_EXPR_DECL(SIOPBO, SIOPBO, AB21_DESC); +SIG_EXPR_DECL(SIOPBO, ACPI, AB21_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOPBO, SIOPBO, ACPI); +SIG_EXPR_LIST_DECL_SINGLE(NORA2, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOZ2, GPIOZ2); +MS_PIN_DECL_(AB21, SIG_EXPR_LIST_PTR(VPOG4), SIG_EXPR_LIST_PTR(SIOPBO), + SIG_EXPR_LIST_PTR(NORA2), SIG_EXPR_LIST_PTR(GPIOZ2)); +FUNC_GROUP_DECL(SIOPBO, AB21); + +#define AA21 203 +#define AA21_DESC SIG_DESC_SET(SCUA4, 19) +SIG_EXPR_DECL(VPOG5, VPO, AA21_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOG5, VPOOFF1, AA21_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOG5, VPOOFF2, AA21_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOG5, SIG_EXPR_PTR(VPOG5, VPO), + SIG_EXPR_PTR(VPOG5, VPOOFF1), SIG_EXPR_PTR(VPOG5, VPOOFF2)); +SIG_EXPR_DECL(SIOSCI, SIOSCI, AA21_DESC); +SIG_EXPR_DECL(SIOSCI, ACPI, AA21_DESC); +SIG_EXPR_LIST_DECL_DUAL(SIOSCI, SIOSCI, ACPI); +SIG_EXPR_LIST_DECL_SINGLE(NORA3, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOZ3, GPIOZ3); +MS_PIN_DECL_(AA21, SIG_EXPR_LIST_PTR(VPOG5), SIG_EXPR_LIST_PTR(SIOSCI), + SIG_EXPR_LIST_PTR(NORA3), SIG_EXPR_LIST_PTR(GPIOZ3)); +FUNC_GROUP_DECL(SIOSCI, AA21); + +FUNC_GROUP_DECL(ACPI, R22, R21, P22, P21, Y20, AB20, AB21, AA21); + +/* CRT DVO disabled, configured for single-edge mode */ +#define CRT_DVO_DS_DESC { ASPEED_IP_GFX, GFX064, GENMASK(7, 6), 0, 0 } + +/* CRT DVO disabled, configured for dual-edge mode */ +#define CRT_DVO_DD_DESC { ASPEED_IP_GFX, GFX064, GENMASK(7, 6), 1, 1 } + +/* CRT DVO enabled, configured for single-edge mode */ +#define CRT_DVO_ES_DESC { ASPEED_IP_GFX, GFX064, GENMASK(7, 6), 2, 2 } + +/* CRT DVO enabled, configured for dual-edge mode */ +#define CRT_DVO_ED_DESC { ASPEED_IP_GFX, GFX064, GENMASK(7, 6), 3, 3 } + +#define U21 204 +#define U21_DESC SIG_DESC_SET(SCUA4, 20) +SIG_EXPR_DECL(VPOG6, VPO, U21_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOG6, VPOOFF1, U21_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOG6, VPOOFF2, U21_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOG6, SIG_EXPR_PTR(VPOG6, VPO), + SIG_EXPR_PTR(VPOG6, VPOOFF1), SIG_EXPR_PTR(VPOG6, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(NORA4, PNOR, PNOR_DESC); +MS_PIN_DECL(U21, GPIOZ4, VPOG6, NORA4); + +#define W22 205 +#define W22_DESC SIG_DESC_SET(SCUA4, 21) +SIG_EXPR_DECL(VPOG7, VPO, W22_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOG7, VPOOFF1, W22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOG7, VPOOFF2, W22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOG7, SIG_EXPR_PTR(VPOG7, VPO), + SIG_EXPR_PTR(VPOG7, VPOOFF1), SIG_EXPR_PTR(VPOG7, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(NORA5, PNOR, PNOR_DESC); +MS_PIN_DECL(W22, GPIOZ5, VPOG7, NORA5); + +#define V22 206 +#define V22_DESC SIG_DESC_SET(SCUA4, 22) +SIG_EXPR_DECL(VPOG8, VPO, V22_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOG8, VPOOFF1, V22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOG8, VPOOFF2, V22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOG8, SIG_EXPR_PTR(VPOG8, VPO), + SIG_EXPR_PTR(VPOG8, VPOOFF1), SIG_EXPR_PTR(VPOG8, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(NORA6, PNOR, PNOR_DESC); +MS_PIN_DECL(V22, GPIOZ6, VPOG8, NORA6); + +#define W21 207 +#define W21_DESC SIG_DESC_SET(SCUA4, 23) +SIG_EXPR_DECL(VPOG9, VPO, W21_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOG9, VPOOFF1, W21_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOG9, VPOOFF2, W21_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOG9, SIG_EXPR_PTR(VPOG9, VPO), + SIG_EXPR_PTR(VPOG9, VPOOFF1), SIG_EXPR_PTR(VPOG9, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(NORA7, PNOR, PNOR_DESC); +MS_PIN_DECL(W21, GPIOZ7, VPOG9, NORA7); + +#define Y21 208 +#define Y21_DESC SIG_DESC_SET(SCUA4, 24) +SIG_EXPR_DECL(VPOR2, VPO, Y21_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR2, VPOOFF1, Y21_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR2, VPOOFF2, Y21_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOR2, SIG_EXPR_PTR(VPOR2, VPO), + SIG_EXPR_PTR(VPOR2, VPOOFF1), SIG_EXPR_PTR(VPOR2, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT7, SALT7, Y21_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NORD0, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOAA0, GPIOAA0); +MS_PIN_DECL_(Y21, SIG_EXPR_LIST_PTR(VPOR2), SIG_EXPR_LIST_PTR(SALT7), + SIG_EXPR_LIST_PTR(NORD0), SIG_EXPR_LIST_PTR(GPIOAA0)); +FUNC_GROUP_DECL(SALT7, Y21); + +#define V21 209 +#define V21_DESC SIG_DESC_SET(SCUA4, 25) +SIG_EXPR_DECL(VPOR3, VPO, V21_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR3, VPOOFF1, V21_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR3, VPOOFF2, V21_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOR3, SIG_EXPR_PTR(VPOR3, VPO), + SIG_EXPR_PTR(VPOR3, VPOOFF1), SIG_EXPR_PTR(VPOR3, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT8, SALT8, V21_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NORD1, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOAA1, GPIOAA1); +MS_PIN_DECL_(V21, SIG_EXPR_LIST_PTR(VPOR3), SIG_EXPR_LIST_PTR(SALT8), + SIG_EXPR_LIST_PTR(NORD1), SIG_EXPR_LIST_PTR(GPIOAA1)); +FUNC_GROUP_DECL(SALT8, V21); + +#define Y22 210 +#define Y22_DESC SIG_DESC_SET(SCUA4, 26) +SIG_EXPR_DECL(VPOR4, VPO, Y22_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR4, VPOOFF1, Y22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR4, VPOOFF2, Y22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOR4, SIG_EXPR_PTR(VPOR4, VPO), + SIG_EXPR_PTR(VPOR4, VPOOFF1), SIG_EXPR_PTR(VPOR4, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT9, SALT9, Y22_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NORD2, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOAA2, GPIOAA2); +MS_PIN_DECL_(Y22, SIG_EXPR_LIST_PTR(VPOR4), SIG_EXPR_LIST_PTR(SALT9), + SIG_EXPR_LIST_PTR(NORD2), SIG_EXPR_LIST_PTR(GPIOAA2)); +FUNC_GROUP_DECL(SALT9, Y22); + +#define AA22 211 +#define AA22_DESC SIG_DESC_SET(SCUA4, 27) +SIG_EXPR_DECL(VPOR5, VPO, AA22_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR5, VPOOFF1, AA22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR5, VPOOFF2, AA22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOR5, SIG_EXPR_PTR(VPOR5, VPO), + SIG_EXPR_PTR(VPOR5, VPOOFF1), SIG_EXPR_PTR(VPOR5, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT10, SALT10, AA22_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NORD3, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOAA3, GPIOAA3); +MS_PIN_DECL_(AA22, SIG_EXPR_LIST_PTR(VPOR5), SIG_EXPR_LIST_PTR(SALT10), + SIG_EXPR_LIST_PTR(NORD3), SIG_EXPR_LIST_PTR(GPIOAA3)); +FUNC_GROUP_DECL(SALT10, AA22); + +#define U22 212 +#define U22_DESC SIG_DESC_SET(SCUA4, 28) +SIG_EXPR_DECL(VPOR6, VPO, U22_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR6, VPOOFF1, U22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR6, VPOOFF2, U22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOR6, SIG_EXPR_PTR(VPOR6, VPO), + SIG_EXPR_PTR(VPOR6, VPOOFF1), SIG_EXPR_PTR(VPOR6, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT11, SALT11, U22_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NORD4, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOAA4, GPIOAA4); +MS_PIN_DECL_(U22, SIG_EXPR_LIST_PTR(VPOR6), SIG_EXPR_LIST_PTR(SALT11), + SIG_EXPR_LIST_PTR(NORD4), SIG_EXPR_LIST_PTR(GPIOAA4)); +FUNC_GROUP_DECL(SALT11, U22); + +#define T20 213 +#define T20_DESC SIG_DESC_SET(SCUA4, 29) +SIG_EXPR_DECL(VPOR7, VPO, T20_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR7, VPOOFF1, T20_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR7, VPOOFF2, T20_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOR7, SIG_EXPR_PTR(VPOR7, VPO), + SIG_EXPR_PTR(VPOR7, VPOOFF1), SIG_EXPR_PTR(VPOR7, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT12, SALT12, T20_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NORD5, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOAA5, GPIOAA5); +MS_PIN_DECL_(T20, SIG_EXPR_LIST_PTR(VPOR7), SIG_EXPR_LIST_PTR(SALT12), + SIG_EXPR_LIST_PTR(NORD5), SIG_EXPR_LIST_PTR(GPIOAA5)); +FUNC_GROUP_DECL(SALT12, T20); + +#define N18 214 +#define N18_DESC SIG_DESC_SET(SCUA4, 30) +SIG_EXPR_DECL(VPOR8, VPO, N18_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR8, VPOOFF1, N18_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR8, VPOOFF2, N18_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOR8, SIG_EXPR_PTR(VPOR8, VPO), + SIG_EXPR_PTR(VPOR8, VPOOFF1), SIG_EXPR_PTR(VPOR8, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT13, SALT13, N18_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NORD6, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOAA6, GPIOAA6); +MS_PIN_DECL_(N18, SIG_EXPR_LIST_PTR(VPOR8), SIG_EXPR_LIST_PTR(SALT13), + SIG_EXPR_LIST_PTR(NORD6), SIG_EXPR_LIST_PTR(GPIOAA6)); +FUNC_GROUP_DECL(SALT13, N18); + +#define P19 215 +#define P19_DESC SIG_DESC_SET(SCUA4, 31) +SIG_EXPR_DECL(VPOR9, VPO, P19_DESC, VPO_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR9, VPOOFF1, P19_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_DECL(VPOR9, VPOOFF2, P19_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC); +SIG_EXPR_LIST_DECL(VPOR9, SIG_EXPR_PTR(VPOR9, VPO), + SIG_EXPR_PTR(VPOR9, VPOOFF1), SIG_EXPR_PTR(VPOR9, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(SALT14, SALT14, P19_DESC); +SIG_EXPR_LIST_DECL_SINGLE(NORD7, PNOR, PNOR_DESC); +SIG_EXPR_LIST_DECL_SINGLE(GPIOAA7, GPIOAA7); +MS_PIN_DECL_(P19, SIG_EXPR_LIST_PTR(VPOR9), SIG_EXPR_LIST_PTR(SALT14), + SIG_EXPR_LIST_PTR(NORD7), SIG_EXPR_LIST_PTR(GPIOAA7)); +FUNC_GROUP_DECL(SALT14, P19); + +#define N19 216 +#define N19_DESC SIG_DESC_SET(SCUA8, 0) +SIG_EXPR_DECL(VPODE, VPO, N19_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPODE, VPOOFF1, N19_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPODE, VPOOFF2, N19_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPODE, SIG_EXPR_PTR(VPODE, VPO), + SIG_EXPR_PTR(VPODE, VPOOFF1), SIG_EXPR_PTR(VPODE, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(NOROE, PNOR, PNOR_DESC); +MS_PIN_DECL(N19, GPIOAB0, VPODE, NOROE); + +#define T21 217 +#define T21_DESC SIG_DESC_SET(SCUA8, 1) +SIG_EXPR_DECL(VPOHS, VPO, T21_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOHS, VPOOFF1, T21_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOHS, VPOOFF2, T21_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOHS, SIG_EXPR_PTR(VPOHS, VPO), + SIG_EXPR_PTR(VPOHS, VPOOFF1), SIG_EXPR_PTR(VPOHS, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(NORWE, PNOR, PNOR_DESC); +MS_PIN_DECL(T21, GPIOAB1, VPOHS, NORWE); + +FUNC_GROUP_DECL(PNOR, Y20, AB20, AB21, AA21, U21, W22, V22, W21, Y21, V21, Y22, + AA22, U22, T20, N18, P19, N19, T21); + +#define T22 218 +#define T22_DESC SIG_DESC_SET(SCUA8, 2) +SIG_EXPR_DECL(VPOVS, VPO, T22_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOVS, VPOOFF1, T22_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOVS, VPOOFF2, T22_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOVS, SIG_EXPR_PTR(VPOVS, VPO), + SIG_EXPR_PTR(VPOVS, VPOOFF1), SIG_EXPR_PTR(VPOVS, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(WDTRST1, WDTRST1, T22_DESC); +MS_PIN_DECL(T22, GPIOAB2, VPOVS, WDTRST1); +FUNC_GROUP_DECL(WDTRST1, T22); + +#define R20 219 +#define R20_DESC SIG_DESC_SET(SCUA8, 3) +SIG_EXPR_DECL(VPOCLK, VPO, R20_DESC, VPO_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOCLK, VPOOFF1, R20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_DECL(VPOCLK, VPOOFF2, R20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC); +SIG_EXPR_LIST_DECL(VPOCLK, SIG_EXPR_PTR(VPOCLK, VPO), + SIG_EXPR_PTR(VPOCLK, VPOOFF1), SIG_EXPR_PTR(VPOCLK, VPOOFF2)); +SIG_EXPR_LIST_DECL_SINGLE(WDTRST2, WDTRST2, R20_DESC); +MS_PIN_DECL(R20, GPIOAB3, VPOCLK, WDTRST2); +FUNC_GROUP_DECL(WDTRST2, R20); + +FUNC_GROUP_DECL(VPO, V20, U19, R18, P18, R19, W20, U20, AA20, Y20, AB20, + AB21, AA21, U21, W22, V22, W21, Y21, V21, Y22, AA22, U22, T20, + N18, P19, N19, T21, T22, R20); + +#define ESPI_DESC SIG_DESC_SET(HW_STRAP1, 25) + +#define G21 224 +SIG_EXPR_LIST_DECL_SINGLE(ESPID0, ESPI, ESPI_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LAD0, LAD0, SIG_DESC_SET(SCUAC, 0)); +MS_PIN_DECL(G21, GPIOAC0, ESPID0, LAD0); +FUNC_GROUP_DECL(LAD0, G21); + +#define G20 225 +SIG_EXPR_LIST_DECL_SINGLE(ESPID1, ESPI, ESPI_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LAD1, LAD1, SIG_DESC_SET(SCUAC, 1)); +MS_PIN_DECL(G20, GPIOAC1, ESPID1, LAD1); +FUNC_GROUP_DECL(LAD1, G20); + +#define D22 226 +SIG_EXPR_LIST_DECL_SINGLE(ESPID2, ESPI, ESPI_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LAD2, LAD2, SIG_DESC_SET(SCUAC, 2)); +MS_PIN_DECL(D22, GPIOAC2, ESPID2, LAD2); +FUNC_GROUP_DECL(LAD2, D22); + +#define E22 227 +SIG_EXPR_LIST_DECL_SINGLE(ESPID3, ESPI, ESPI_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LAD3, LAD3, SIG_DESC_SET(SCUAC, 3)); +MS_PIN_DECL(E22, GPIOAC3, ESPID3, LAD3); +FUNC_GROUP_DECL(LAD3, E22); + +#define C22 228 +SIG_EXPR_LIST_DECL_SINGLE(ESPICK, ESPI, ESPI_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LCLK, LCLK, SIG_DESC_SET(SCUAC, 4)); +MS_PIN_DECL(C22, GPIOAC4, ESPICK, LCLK); +FUNC_GROUP_DECL(LCLK, C22); + +#define F21 229 +SIG_EXPR_LIST_DECL_SINGLE(ESPICS, ESPI, ESPI_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LFRAME, LFRAME, SIG_DESC_SET(SCUAC, 5)); +MS_PIN_DECL(F21, GPIOAC5, ESPICS, LFRAME); +FUNC_GROUP_DECL(LFRAME, F21); + +#define F22 230 +SIG_EXPR_LIST_DECL_SINGLE(ESPIALT, ESPI, ESPI_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LSIRQ, LSIRQ, SIG_DESC_SET(SCUAC, 6)); +MS_PIN_DECL(F22, GPIOAC6, ESPIALT, LSIRQ); +FUNC_GROUP_DECL(LSIRQ, F22); + +#define G22 231 +SIG_EXPR_LIST_DECL_SINGLE(ESPIRST, ESPI, ESPI_DESC); +SIG_EXPR_LIST_DECL_SINGLE(LPCRST, LPCRST, SIG_DESC_SET(SCUAC, 7)); +MS_PIN_DECL(G22, GPIOAC7, ESPIRST, LPCRST); +FUNC_GROUP_DECL(LPCRST, G22); + +FUNC_GROUP_DECL(ESPI, G21, G20, D22, E22, C22, F21, F22, G22); + /* Pins, groups and functions are sort(1):ed alphabetically for sanity */ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { @@ -646,12 +1733,32 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { ASPEED_PINCTRL_PIN(A13), ASPEED_PINCTRL_PIN(A14), ASPEED_PINCTRL_PIN(A15), + ASPEED_PINCTRL_PIN(A16), + ASPEED_PINCTRL_PIN(A17), + ASPEED_PINCTRL_PIN(A18), + ASPEED_PINCTRL_PIN(A19), ASPEED_PINCTRL_PIN(A2), + ASPEED_PINCTRL_PIN(A20), + ASPEED_PINCTRL_PIN(A21), ASPEED_PINCTRL_PIN(A3), ASPEED_PINCTRL_PIN(A4), ASPEED_PINCTRL_PIN(A5), ASPEED_PINCTRL_PIN(A9), + ASPEED_PINCTRL_PIN(AA1), + ASPEED_PINCTRL_PIN(AA19), + ASPEED_PINCTRL_PIN(AA2), + ASPEED_PINCTRL_PIN(AA20), + ASPEED_PINCTRL_PIN(AA21), + ASPEED_PINCTRL_PIN(AA22), ASPEED_PINCTRL_PIN(AA3), + ASPEED_PINCTRL_PIN(AA4), + ASPEED_PINCTRL_PIN(AA5), + ASPEED_PINCTRL_PIN(AB2), + ASPEED_PINCTRL_PIN(AB20), + ASPEED_PINCTRL_PIN(AB21), + ASPEED_PINCTRL_PIN(AB3), + ASPEED_PINCTRL_PIN(AB4), + ASPEED_PINCTRL_PIN(AB5), ASPEED_PINCTRL_PIN(B1), ASPEED_PINCTRL_PIN(B10), ASPEED_PINCTRL_PIN(B11), @@ -660,8 +1767,13 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { ASPEED_PINCTRL_PIN(B14), ASPEED_PINCTRL_PIN(B15), ASPEED_PINCTRL_PIN(B16), + ASPEED_PINCTRL_PIN(B17), + ASPEED_PINCTRL_PIN(B18), + ASPEED_PINCTRL_PIN(B19), ASPEED_PINCTRL_PIN(B2), ASPEED_PINCTRL_PIN(B20), + ASPEED_PINCTRL_PIN(B21), + ASPEED_PINCTRL_PIN(B22), ASPEED_PINCTRL_PIN(B3), ASPEED_PINCTRL_PIN(B4), ASPEED_PINCTRL_PIN(B5), @@ -673,62 +1785,210 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = { ASPEED_PINCTRL_PIN(C14), ASPEED_PINCTRL_PIN(C15), ASPEED_PINCTRL_PIN(C16), + ASPEED_PINCTRL_PIN(C17), ASPEED_PINCTRL_PIN(C18), + ASPEED_PINCTRL_PIN(C19), ASPEED_PINCTRL_PIN(C2), ASPEED_PINCTRL_PIN(C20), + ASPEED_PINCTRL_PIN(C21), + ASPEED_PINCTRL_PIN(C22), ASPEED_PINCTRL_PIN(C3), ASPEED_PINCTRL_PIN(C4), ASPEED_PINCTRL_PIN(C5), ASPEED_PINCTRL_PIN(D1), ASPEED_PINCTRL_PIN(D10), + ASPEED_PINCTRL_PIN(D13), + ASPEED_PINCTRL_PIN(D14), + ASPEED_PINCTRL_PIN(D15), + ASPEED_PINCTRL_PIN(D16), + ASPEED_PINCTRL_PIN(D17), + ASPEED_PINCTRL_PIN(D18), + ASPEED_PINCTRL_PIN(D19), ASPEED_PINCTRL_PIN(D2), ASPEED_PINCTRL_PIN(D20), + ASPEED_PINCTRL_PIN(D21), + ASPEED_PINCTRL_PIN(D22), ASPEED_PINCTRL_PIN(D4), ASPEED_PINCTRL_PIN(D5), ASPEED_PINCTRL_PIN(D6), ASPEED_PINCTRL_PIN(D7), ASPEED_PINCTRL_PIN(D8), ASPEED_PINCTRL_PIN(D9), + ASPEED_PINCTRL_PIN(E1), ASPEED_PINCTRL_PIN(E10), ASPEED_PINCTRL_PIN(E12), ASPEED_PINCTRL_PIN(E13), + ASPEED_PINCTRL_PIN(E14), ASPEED_PINCTRL_PIN(E15), + ASPEED_PINCTRL_PIN(E16), + ASPEED_PINCTRL_PIN(E17), + ASPEED_PINCTRL_PIN(E18), + ASPEED_PINCTRL_PIN(E19), + ASPEED_PINCTRL_PIN(E2), + ASPEED_PINCTRL_PIN(E20), ASPEED_PINCTRL_PIN(E21), + ASPEED_PINCTRL_PIN(E22), + ASPEED_PINCTRL_PIN(E3), ASPEED_PINCTRL_PIN(E6), ASPEED_PINCTRL_PIN(E7), ASPEED_PINCTRL_PIN(E9), + ASPEED_PINCTRL_PIN(F1), + ASPEED_PINCTRL_PIN(F17), + ASPEED_PINCTRL_PIN(F18), ASPEED_PINCTRL_PIN(F19), + ASPEED_PINCTRL_PIN(F2), ASPEED_PINCTRL_PIN(F20), + ASPEED_PINCTRL_PIN(F21), + ASPEED_PINCTRL_PIN(F22), + ASPEED_PINCTRL_PIN(F3), + ASPEED_PINCTRL_PIN(F4), + ASPEED_PINCTRL_PIN(F5), ASPEED_PINCTRL_PIN(F9), + ASPEED_PINCTRL_PIN(G1), + ASPEED_PINCTRL_PIN(G17), + ASPEED_PINCTRL_PIN(G18), + ASPEED_PINCTRL_PIN(G2), + ASPEED_PINCTRL_PIN(G20), + ASPEED_PINCTRL_PIN(G21), + ASPEED_PINCTRL_PIN(G22), + ASPEED_PINCTRL_PIN(G3), + ASPEED_PINCTRL_PIN(G4), + ASPEED_PINCTRL_PIN(G5), + ASPEED_PINCTRL_PIN(H18), + ASPEED_PINCTRL_PIN(H19), ASPEED_PINCTRL_PIN(H20), + ASPEED_PINCTRL_PIN(H21), + ASPEED_PINCTRL_PIN(H22), + ASPEED_PINCTRL_PIN(H3), + ASPEED_PINCTRL_PIN(H4), + ASPEED_PINCTRL_PIN(H5), + ASPEED_PINCTRL_PIN(J18), + ASPEED_PINCTRL_PIN(J19), + ASPEED_PINCTRL_PIN(J20), + ASPEED_PINCTRL_PIN(K18), + ASPEED_PINCTRL_PIN(K19), ASPEED_PINCTRL_PIN(L1), + ASPEED_PINCTRL_PIN(L18), + ASPEED_PINCTRL_PIN(L19), ASPEED_PINCTRL_PIN(L2), ASPEED_PINCTRL_PIN(L3), ASPEED_PINCTRL_PIN(L4), + ASPEED_PINCTRL_PIN(M18), + ASPEED_PINCTRL_PIN(M19), + ASPEED_PINCTRL_PIN(M20), ASPEED_PINCTRL_PIN(N1), + ASPEED_PINCTRL_PIN(N18), + ASPEED_PINCTRL_PIN(N19), ASPEED_PINCTRL_PIN(N2), ASPEED_PINCTRL_PIN(N20), ASPEED_PINCTRL_PIN(N21), ASPEED_PINCTRL_PIN(N22), ASPEED_PINCTRL_PIN(N3), ASPEED_PINCTRL_PIN(N4), + ASPEED_PINCTRL_PIN(N5), ASPEED_PINCTRL_PIN(P1), + ASPEED_PINCTRL_PIN(P18), + ASPEED_PINCTRL_PIN(P19), ASPEED_PINCTRL_PIN(P2), + ASPEED_PINCTRL_PIN(P20), + ASPEED_PINCTRL_PIN(P21), + ASPEED_PINCTRL_PIN(P22), + ASPEED_PINCTRL_PIN(P3), + ASPEED_PINCTRL_PIN(P4), + ASPEED_PINCTRL_PIN(P5), ASPEED_PINCTRL_PIN(R1), + ASPEED_PINCTRL_PIN(R18), + ASPEED_PINCTRL_PIN(R19), + ASPEED_PINCTRL_PIN(R2), + ASPEED_PINCTRL_PIN(R20), + ASPEED_PINCTRL_PIN(R21), + ASPEED_PINCTRL_PIN(R22), + ASPEED_PINCTRL_PIN(R3), + ASPEED_PINCTRL_PIN(R4), + ASPEED_PINCTRL_PIN(R5), + ASPEED_PINCTRL_PIN(T1), + ASPEED_PINCTRL_PIN(T17), + ASPEED_PINCTRL_PIN(T19), + ASPEED_PINCTRL_PIN(T2), + ASPEED_PINCTRL_PIN(T20), + ASPEED_PINCTRL_PIN(T21), + ASPEED_PINCTRL_PIN(T22), + ASPEED_PINCTRL_PIN(T3), ASPEED_PINCTRL_PIN(T4), + ASPEED_PINCTRL_PIN(T5), + ASPEED_PINCTRL_PIN(U1), + ASPEED_PINCTRL_PIN(U19), + ASPEED_PINCTRL_PIN(U2), + ASPEED_PINCTRL_PIN(U20), + ASPEED_PINCTRL_PIN(U21), + ASPEED_PINCTRL_PIN(U22), ASPEED_PINCTRL_PIN(U3), + ASPEED_PINCTRL_PIN(U4), + ASPEED_PINCTRL_PIN(U5), + ASPEED_PINCTRL_PIN(V1), + ASPEED_PINCTRL_PIN(V19), ASPEED_PINCTRL_PIN(V2), + ASPEED_PINCTRL_PIN(V20), + ASPEED_PINCTRL_PIN(V21), + ASPEED_PINCTRL_PIN(V22), ASPEED_PINCTRL_PIN(V3), + ASPEED_PINCTRL_PIN(V4), + ASPEED_PINCTRL_PIN(V5), ASPEED_PINCTRL_PIN(V6), + ASPEED_PINCTRL_PIN(W1), + ASPEED_PINCTRL_PIN(W19), ASPEED_PINCTRL_PIN(W2), + ASPEED_PINCTRL_PIN(W20), + ASPEED_PINCTRL_PIN(W21), + ASPEED_PINCTRL_PIN(W22), ASPEED_PINCTRL_PIN(W3), + ASPEED_PINCTRL_PIN(W4), + ASPEED_PINCTRL_PIN(W5), + ASPEED_PINCTRL_PIN(W6), + ASPEED_PINCTRL_PIN(Y1), + ASPEED_PINCTRL_PIN(Y19), + ASPEED_PINCTRL_PIN(Y2), + ASPEED_PINCTRL_PIN(Y20), + ASPEED_PINCTRL_PIN(Y21), + ASPEED_PINCTRL_PIN(Y22), ASPEED_PINCTRL_PIN(Y3), + ASPEED_PINCTRL_PIN(Y4), + ASPEED_PINCTRL_PIN(Y5), + ASPEED_PINCTRL_PIN(Y6), }; static const struct aspeed_pin_group aspeed_g5_groups[] = { + ASPEED_PINCTRL_GROUP(ACPI), + ASPEED_PINCTRL_GROUP(ADC0), + ASPEED_PINCTRL_GROUP(ADC1), + ASPEED_PINCTRL_GROUP(ADC10), + ASPEED_PINCTRL_GROUP(ADC11), + ASPEED_PINCTRL_GROUP(ADC12), + ASPEED_PINCTRL_GROUP(ADC13), + ASPEED_PINCTRL_GROUP(ADC14), + ASPEED_PINCTRL_GROUP(ADC15), + ASPEED_PINCTRL_GROUP(ADC2), + ASPEED_PINCTRL_GROUP(ADC3), + ASPEED_PINCTRL_GROUP(ADC4), + ASPEED_PINCTRL_GROUP(ADC5), + ASPEED_PINCTRL_GROUP(ADC6), + ASPEED_PINCTRL_GROUP(ADC7), + ASPEED_PINCTRL_GROUP(ADC8), + ASPEED_PINCTRL_GROUP(ADC9), + ASPEED_PINCTRL_GROUP(BMCINT), + ASPEED_PINCTRL_GROUP(DDCCLK), + ASPEED_PINCTRL_GROUP(DDCDAT), + ASPEED_PINCTRL_GROUP(ESPI), + ASPEED_PINCTRL_GROUP(FWSPICS1), + ASPEED_PINCTRL_GROUP(FWSPICS2), ASPEED_PINCTRL_GROUP(GPID0), ASPEED_PINCTRL_GROUP(GPID2), + ASPEED_PINCTRL_GROUP(GPID4), + ASPEED_PINCTRL_GROUP(GPID6), ASPEED_PINCTRL_GROUP(GPIE0), + ASPEED_PINCTRL_GROUP(GPIE2), + ASPEED_PINCTRL_GROUP(GPIE4), + ASPEED_PINCTRL_GROUP(GPIE6), ASPEED_PINCTRL_GROUP(I2C10), ASPEED_PINCTRL_GROUP(I2C11), ASPEED_PINCTRL_GROUP(I2C12), @@ -741,11 +2001,50 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = { ASPEED_PINCTRL_GROUP(I2C7), ASPEED_PINCTRL_GROUP(I2C8), ASPEED_PINCTRL_GROUP(I2C9), + ASPEED_PINCTRL_GROUP(LAD0), + ASPEED_PINCTRL_GROUP(LAD1), + ASPEED_PINCTRL_GROUP(LAD2), + ASPEED_PINCTRL_GROUP(LAD3), + ASPEED_PINCTRL_GROUP(LCLK), + ASPEED_PINCTRL_GROUP(LFRAME), + ASPEED_PINCTRL_GROUP(LPCHC), + ASPEED_PINCTRL_GROUP(LPCPD), + ASPEED_PINCTRL_GROUP(LPCPLUS), + ASPEED_PINCTRL_GROUP(LPCPME), + ASPEED_PINCTRL_GROUP(LPCRST), + ASPEED_PINCTRL_GROUP(LPCSMI), + ASPEED_PINCTRL_GROUP(LSIRQ), ASPEED_PINCTRL_GROUP(MAC1LINK), + ASPEED_PINCTRL_GROUP(MAC2LINK), ASPEED_PINCTRL_GROUP(MDIO1), ASPEED_PINCTRL_GROUP(MDIO2), + ASPEED_PINCTRL_GROUP(NCTS1), + ASPEED_PINCTRL_GROUP(NCTS2), + ASPEED_PINCTRL_GROUP(NCTS3), + ASPEED_PINCTRL_GROUP(NCTS4), + ASPEED_PINCTRL_GROUP(NDCD1), + ASPEED_PINCTRL_GROUP(NDCD2), + ASPEED_PINCTRL_GROUP(NDCD3), + ASPEED_PINCTRL_GROUP(NDCD4), + ASPEED_PINCTRL_GROUP(NDSR1), + ASPEED_PINCTRL_GROUP(NDSR2), + ASPEED_PINCTRL_GROUP(NDSR3), + ASPEED_PINCTRL_GROUP(NDSR4), + ASPEED_PINCTRL_GROUP(NDTR1), + ASPEED_PINCTRL_GROUP(NDTR2), + ASPEED_PINCTRL_GROUP(NDTR3), + ASPEED_PINCTRL_GROUP(NDTR4), + ASPEED_PINCTRL_GROUP(NRI1), + ASPEED_PINCTRL_GROUP(NRI2), + ASPEED_PINCTRL_GROUP(NRI3), + ASPEED_PINCTRL_GROUP(NRI4), + ASPEED_PINCTRL_GROUP(NRTS1), + ASPEED_PINCTRL_GROUP(NRTS2), + ASPEED_PINCTRL_GROUP(NRTS3), + ASPEED_PINCTRL_GROUP(NRTS4), ASPEED_PINCTRL_GROUP(OSCCLK), ASPEED_PINCTRL_GROUP(PEWAKE), + ASPEED_PINCTRL_GROUP(PNOR), ASPEED_PINCTRL_GROUP(PWM0), ASPEED_PINCTRL_GROUP(PWM1), ASPEED_PINCTRL_GROUP(PWM2), @@ -758,22 +2057,102 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = { ASPEED_PINCTRL_GROUP(RGMII2), ASPEED_PINCTRL_GROUP(RMII1), ASPEED_PINCTRL_GROUP(RMII2), + ASPEED_PINCTRL_GROUP(RXD1), + ASPEED_PINCTRL_GROUP(RXD2), + ASPEED_PINCTRL_GROUP(RXD3), + ASPEED_PINCTRL_GROUP(RXD4), + ASPEED_PINCTRL_GROUP(SALT1), + ASPEED_PINCTRL_GROUP(SALT10), + ASPEED_PINCTRL_GROUP(SALT11), + ASPEED_PINCTRL_GROUP(SALT12), + ASPEED_PINCTRL_GROUP(SALT13), + ASPEED_PINCTRL_GROUP(SALT14), + ASPEED_PINCTRL_GROUP(SALT2), + ASPEED_PINCTRL_GROUP(SALT3), + ASPEED_PINCTRL_GROUP(SALT4), + ASPEED_PINCTRL_GROUP(SALT5), + ASPEED_PINCTRL_GROUP(SALT6), + ASPEED_PINCTRL_GROUP(SALT7), + ASPEED_PINCTRL_GROUP(SALT8), + ASPEED_PINCTRL_GROUP(SALT9), + ASPEED_PINCTRL_GROUP(SCL1), + ASPEED_PINCTRL_GROUP(SCL2), ASPEED_PINCTRL_GROUP(SD1), + ASPEED_PINCTRL_GROUP(SD2), + ASPEED_PINCTRL_GROUP(SDA1), + ASPEED_PINCTRL_GROUP(SDA2), + ASPEED_PINCTRL_GROUP(SGPS1), + ASPEED_PINCTRL_GROUP(SGPS2), + ASPEED_PINCTRL_GROUP(SIOONCTRL), + ASPEED_PINCTRL_GROUP(SIOPBI), + ASPEED_PINCTRL_GROUP(SIOPBO), + ASPEED_PINCTRL_GROUP(SIOPWREQ), + ASPEED_PINCTRL_GROUP(SIOPWRGD), + ASPEED_PINCTRL_GROUP(SIOS3), + ASPEED_PINCTRL_GROUP(SIOS5), + ASPEED_PINCTRL_GROUP(SIOSCI), ASPEED_PINCTRL_GROUP(SPI1), + ASPEED_PINCTRL_GROUP(SPI1CS1), ASPEED_PINCTRL_GROUP(SPI1DEBUG), ASPEED_PINCTRL_GROUP(SPI1PASSTHRU), + ASPEED_PINCTRL_GROUP(SPI2CK), + ASPEED_PINCTRL_GROUP(SPI2CS0), + ASPEED_PINCTRL_GROUP(SPI2CS1), + ASPEED_PINCTRL_GROUP(SPI2MISO), + ASPEED_PINCTRL_GROUP(SPI2MOSI), + ASPEED_PINCTRL_GROUP(TIMER3), ASPEED_PINCTRL_GROUP(TIMER4), ASPEED_PINCTRL_GROUP(TIMER5), ASPEED_PINCTRL_GROUP(TIMER6), ASPEED_PINCTRL_GROUP(TIMER7), ASPEED_PINCTRL_GROUP(TIMER8), + ASPEED_PINCTRL_GROUP(TXD1), + ASPEED_PINCTRL_GROUP(TXD2), + ASPEED_PINCTRL_GROUP(TXD3), + ASPEED_PINCTRL_GROUP(TXD4), + ASPEED_PINCTRL_GROUP(UART6), + ASPEED_PINCTRL_GROUP(USBCKI), ASPEED_PINCTRL_GROUP(VGABIOSROM), + ASPEED_PINCTRL_GROUP(VGAHS), + ASPEED_PINCTRL_GROUP(VGAVS), + ASPEED_PINCTRL_GROUP(VPI24), + ASPEED_PINCTRL_GROUP(VPO), + ASPEED_PINCTRL_GROUP(WDTRST1), + ASPEED_PINCTRL_GROUP(WDTRST2), }; static const struct aspeed_pin_function aspeed_g5_functions[] = { + ASPEED_PINCTRL_FUNC(ACPI), + ASPEED_PINCTRL_FUNC(ADC0), + ASPEED_PINCTRL_FUNC(ADC1), + ASPEED_PINCTRL_FUNC(ADC10), + ASPEED_PINCTRL_FUNC(ADC11), + ASPEED_PINCTRL_FUNC(ADC12), + ASPEED_PINCTRL_FUNC(ADC13), + ASPEED_PINCTRL_FUNC(ADC14), + ASPEED_PINCTRL_FUNC(ADC15), + ASPEED_PINCTRL_FUNC(ADC2), + ASPEED_PINCTRL_FUNC(ADC3), + ASPEED_PINCTRL_FUNC(ADC4), + ASPEED_PINCTRL_FUNC(ADC5), + ASPEED_PINCTRL_FUNC(ADC6), + ASPEED_PINCTRL_FUNC(ADC7), + ASPEED_PINCTRL_FUNC(ADC8), + ASPEED_PINCTRL_FUNC(ADC9), + ASPEED_PINCTRL_FUNC(BMCINT), + ASPEED_PINCTRL_FUNC(DDCCLK), + ASPEED_PINCTRL_FUNC(DDCDAT), + ASPEED_PINCTRL_FUNC(ESPI), + ASPEED_PINCTRL_FUNC(FWSPICS1), + ASPEED_PINCTRL_FUNC(FWSPICS2), ASPEED_PINCTRL_FUNC(GPID0), ASPEED_PINCTRL_FUNC(GPID2), + ASPEED_PINCTRL_FUNC(GPID4), + ASPEED_PINCTRL_FUNC(GPID6), ASPEED_PINCTRL_FUNC(GPIE0), + ASPEED_PINCTRL_FUNC(GPIE2), + ASPEED_PINCTRL_FUNC(GPIE4), + ASPEED_PINCTRL_FUNC(GPIE6), ASPEED_PINCTRL_FUNC(I2C10), ASPEED_PINCTRL_FUNC(I2C11), ASPEED_PINCTRL_FUNC(I2C12), @@ -786,11 +2165,50 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = { ASPEED_PINCTRL_FUNC(I2C7), ASPEED_PINCTRL_FUNC(I2C8), ASPEED_PINCTRL_FUNC(I2C9), + ASPEED_PINCTRL_FUNC(LAD0), + ASPEED_PINCTRL_FUNC(LAD1), + ASPEED_PINCTRL_FUNC(LAD2), + ASPEED_PINCTRL_FUNC(LAD3), + ASPEED_PINCTRL_FUNC(LCLK), + ASPEED_PINCTRL_FUNC(LFRAME), + ASPEED_PINCTRL_FUNC(LPCHC), + ASPEED_PINCTRL_FUNC(LPCPD), + ASPEED_PINCTRL_FUNC(LPCPLUS), + ASPEED_PINCTRL_FUNC(LPCPME), + ASPEED_PINCTRL_FUNC(LPCRST), + ASPEED_PINCTRL_FUNC(LPCSMI), + ASPEED_PINCTRL_FUNC(LSIRQ), ASPEED_PINCTRL_FUNC(MAC1LINK), + ASPEED_PINCTRL_FUNC(MAC2LINK), ASPEED_PINCTRL_FUNC(MDIO1), ASPEED_PINCTRL_FUNC(MDIO2), + ASPEED_PINCTRL_FUNC(NCTS1), + ASPEED_PINCTRL_FUNC(NCTS2), + ASPEED_PINCTRL_FUNC(NCTS3), + ASPEED_PINCTRL_FUNC(NCTS4), + ASPEED_PINCTRL_FUNC(NDCD1), + ASPEED_PINCTRL_FUNC(NDCD2), + ASPEED_PINCTRL_FUNC(NDCD3), + ASPEED_PINCTRL_FUNC(NDCD4), + ASPEED_PINCTRL_FUNC(NDSR1), + ASPEED_PINCTRL_FUNC(NDSR2), + ASPEED_PINCTRL_FUNC(NDSR3), + ASPEED_PINCTRL_FUNC(NDSR4), + ASPEED_PINCTRL_FUNC(NDTR1), + ASPEED_PINCTRL_FUNC(NDTR2), + ASPEED_PINCTRL_FUNC(NDTR3), + ASPEED_PINCTRL_FUNC(NDTR4), + ASPEED_PINCTRL_FUNC(NRI1), + ASPEED_PINCTRL_FUNC(NRI2), + ASPEED_PINCTRL_FUNC(NRI3), + ASPEED_PINCTRL_FUNC(NRI4), + ASPEED_PINCTRL_FUNC(NRTS1), + ASPEED_PINCTRL_FUNC(NRTS2), + ASPEED_PINCTRL_FUNC(NRTS3), + ASPEED_PINCTRL_FUNC(NRTS4), ASPEED_PINCTRL_FUNC(OSCCLK), ASPEED_PINCTRL_FUNC(PEWAKE), + ASPEED_PINCTRL_FUNC(PNOR), ASPEED_PINCTRL_FUNC(PWM0), ASPEED_PINCTRL_FUNC(PWM1), ASPEED_PINCTRL_FUNC(PWM2), @@ -803,16 +2221,68 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = { ASPEED_PINCTRL_FUNC(RGMII2), ASPEED_PINCTRL_FUNC(RMII1), ASPEED_PINCTRL_FUNC(RMII2), + ASPEED_PINCTRL_FUNC(RXD1), + ASPEED_PINCTRL_FUNC(RXD2), + ASPEED_PINCTRL_FUNC(RXD3), + ASPEED_PINCTRL_FUNC(RXD4), + ASPEED_PINCTRL_FUNC(SALT1), + ASPEED_PINCTRL_FUNC(SALT10), + ASPEED_PINCTRL_FUNC(SALT11), + ASPEED_PINCTRL_FUNC(SALT12), + ASPEED_PINCTRL_FUNC(SALT13), + ASPEED_PINCTRL_FUNC(SALT14), + ASPEED_PINCTRL_FUNC(SALT2), + ASPEED_PINCTRL_FUNC(SALT3), + ASPEED_PINCTRL_FUNC(SALT4), + ASPEED_PINCTRL_FUNC(SALT5), + ASPEED_PINCTRL_FUNC(SALT6), + ASPEED_PINCTRL_FUNC(SALT7), + ASPEED_PINCTRL_FUNC(SALT8), + ASPEED_PINCTRL_FUNC(SALT9), + ASPEED_PINCTRL_FUNC(SCL1), + ASPEED_PINCTRL_FUNC(SCL2), ASPEED_PINCTRL_FUNC(SD1), + ASPEED_PINCTRL_FUNC(SD2), + ASPEED_PINCTRL_FUNC(SDA1), + ASPEED_PINCTRL_FUNC(SDA2), + ASPEED_PINCTRL_FUNC(SGPS1), + ASPEED_PINCTRL_FUNC(SGPS2), + ASPEED_PINCTRL_FUNC(SIOONCTRL), + ASPEED_PINCTRL_FUNC(SIOPBI), + ASPEED_PINCTRL_FUNC(SIOPBO), + ASPEED_PINCTRL_FUNC(SIOPWREQ), + ASPEED_PINCTRL_FUNC(SIOPWRGD), + ASPEED_PINCTRL_FUNC(SIOS3), + ASPEED_PINCTRL_FUNC(SIOS5), + ASPEED_PINCTRL_FUNC(SIOSCI), ASPEED_PINCTRL_FUNC(SPI1), + ASPEED_PINCTRL_FUNC(SPI1CS1), ASPEED_PINCTRL_FUNC(SPI1DEBUG), ASPEED_PINCTRL_FUNC(SPI1PASSTHRU), + ASPEED_PINCTRL_FUNC(SPI2CK), + ASPEED_PINCTRL_FUNC(SPI2CS0), + ASPEED_PINCTRL_FUNC(SPI2CS1), + ASPEED_PINCTRL_FUNC(SPI2MISO), + ASPEED_PINCTRL_FUNC(SPI2MOSI), + ASPEED_PINCTRL_FUNC(TIMER3), ASPEED_PINCTRL_FUNC(TIMER4), ASPEED_PINCTRL_FUNC(TIMER5), ASPEED_PINCTRL_FUNC(TIMER6), ASPEED_PINCTRL_FUNC(TIMER7), ASPEED_PINCTRL_FUNC(TIMER8), + ASPEED_PINCTRL_FUNC(TXD1), + ASPEED_PINCTRL_FUNC(TXD2), + ASPEED_PINCTRL_FUNC(TXD3), + ASPEED_PINCTRL_FUNC(TXD4), + ASPEED_PINCTRL_FUNC(UART6), + ASPEED_PINCTRL_FUNC(USBCKI), ASPEED_PINCTRL_FUNC(VGABIOSROM), + ASPEED_PINCTRL_FUNC(VGAHS), + ASPEED_PINCTRL_FUNC(VGAVS), + ASPEED_PINCTRL_FUNC(VPI24), + ASPEED_PINCTRL_FUNC(VPO), + ASPEED_PINCTRL_FUNC(WDTRST1), + ASPEED_PINCTRL_FUNC(WDTRST2), }; static struct aspeed_pinctrl_data aspeed_g5_pinctrl_data = { diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h index 0e93cbf2ff33..08a10d4db229 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h @@ -260,6 +260,7 @@ #define SCUA0 0xA0 /* Multi-function Pin Control #7 */ #define SCUA4 0xA4 /* Multi-function Pin Control #8 */ #define SCUA8 0xA8 /* Multi-function Pin Control #9 */ +#define SCUAC 0xAC /* Multi-function Pin Control #10 */ #define HW_STRAP2 0xD0 /* Strapping */ /** From b75dd8722e1779767a018009ab6550de33a9136e Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Tue, 20 Dec 2016 18:05:51 +1030 Subject: [PATCH 0028/1587] pinctrl: aspeed: Fix kerneldoc return descriptions Signed-off-by: Andrew Jeffery Acked-by: Joel Stanley Signed-off-by: Linus Walleij --- drivers/pinctrl/aspeed/pinctrl-aspeed.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c index 782c5c97f853..76f62bd45f02 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c @@ -97,7 +97,7 @@ static inline void aspeed_sig_desc_print_val( * @enabled: True to query the enabled state, false to query disabled state * @regmap: The IP block's regmap instance * - * @return 1 if the descriptor's bitfield is configured to the state + * Return: 1 if the descriptor's bitfield is configured to the state * selected by @enabled, 0 if not, and less than zero if an unrecoverable * failure occurred * @@ -134,7 +134,7 @@ static int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, * @enabled: True to query the enabled state, false to query disabled state * @maps: The list of regmap instances * - * @return 1 if the expression composed by @enabled evaluates true, 0 if not, + * Return: 1 if the expression composed by @enabled evaluates true, 0 if not, * and less than zero if an unrecoverable failure occurred. * * A mux function is enabled or disabled if the function's signal expression @@ -175,7 +175,7 @@ static int aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr, * expression, false to disable the function's signal * @maps: The list of regmap instances for pinmux register access. * - * @return 0 if the expression is configured as requested and a negative error + * Return: 0 if the expression is configured as requested and a negative error * code otherwise */ static int aspeed_sig_expr_set(const struct aspeed_sig_expr *expr, @@ -256,7 +256,7 @@ static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr, * @exprs: The list of signal expressions (from a priority level on a pin) * @maps: The list of regmap instances for pinmux register access. * - * @return 0 if all expressions are disabled, otherwise a negative error code + * Return: 0 if all expressions are disabled, otherwise a negative error code */ static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs, struct regmap * const *maps) @@ -281,8 +281,8 @@ static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs, * @exprs: List of signal expressions (haystack) * @name: The name of the requested function (needle) * - * @return A pointer to the signal expression whose function tag matches the - * provided name, otherwise NULL. + * Return: A pointer to the signal expression whose function tag matches the + * provided name, otherwise NULL. * */ static const struct aspeed_sig_expr *aspeed_find_expr_by_name( From 3bfd44306c65d073008b9ca8f062249f35576b61 Mon Sep 17 00:00:00 2001 From: "Shah, Nehal-bakulchandra" Date: Tue, 6 Dec 2016 12:17:48 +0530 Subject: [PATCH 0029/1587] pinctrl: amd: Add support for additional GPIO This patch adds support for new Bank and adds IRQCHIP_SKIP_SET_WAKE flag. Reviewed-by: S-k, Shyam-sundar Signed-off-by: Nehal Shah Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-amd.c | 25 +++++++++++++++---------- drivers/pinctrl/pinctrl-amd.h | 8 +++++--- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index aea310a91821..47b17100410e 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -186,7 +186,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) char *output_value; char *output_enable; - for (bank = 0; bank < AMD_GPIO_TOTAL_BANKS; bank++) { + for (bank = 0; bank < gpio_dev->hwbank_num; bank++) { seq_printf(s, "GPIO bank%d\t", bank); switch (bank) { @@ -202,8 +202,11 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) i = 128; pin_num = AMD_GPIO_PINS_BANK2 + i; break; + case 3: + i = 192; + pin_num = AMD_GPIO_PINS_BANK3 + i; + break; } - for (; i < pin_num; i++) { seq_printf(s, "pin%d\t", i); spin_lock_irqsave(&gpio_dev->lock, flags); @@ -213,7 +216,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) { interrupt_enable = "interrupt is enabled|"; - if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF)) + if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF)) && !(pin_reg & BIT(ACTIVE_LEVEL_OFF+1))) active_level = "Active low|"; else if (pin_reg & BIT(ACTIVE_LEVEL_OFF) @@ -244,17 +247,17 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) interrupt_mask = "interrupt is masked|"; - if (pin_reg & BIT(WAKE_CNTRL_OFF)) + if (pin_reg & BIT(WAKE_CNTRL_OFF_S0I3)) wake_cntrl0 = "enable wakeup in S0i3 state|"; else wake_cntrl0 = "disable wakeup in S0i3 state|"; - if (pin_reg & BIT(WAKE_CNTRL_OFF)) + if (pin_reg & BIT(WAKE_CNTRL_OFF_S3)) wake_cntrl1 = "enable wakeup in S3 state|"; else wake_cntrl1 = "disable wakeup in S3 state|"; - if (pin_reg & BIT(WAKE_CNTRL_OFF)) + if (pin_reg & BIT(WAKE_CNTRL_OFF_S4)) wake_cntrl2 = "enable wakeup in S4/S5 state|"; else wake_cntrl2 = "disable wakeup in S4/S5 state|"; @@ -479,6 +482,7 @@ static struct irq_chip amd_gpio_irqchip = { .irq_unmask = amd_gpio_irq_unmask, .irq_eoi = amd_gpio_irq_eoi, .irq_set_type = amd_gpio_irq_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE, }; static void amd_gpio_irq_handler(struct irq_desc *desc) @@ -764,15 +768,16 @@ static int amd_gpio_probe(struct platform_device *pdev) gpio_dev->gc.set_debounce = amd_gpio_set_debounce; gpio_dev->gc.dbg_show = amd_gpio_dbg_show; - gpio_dev->gc.base = 0; + gpio_dev->gc.base = -1; gpio_dev->gc.label = pdev->name; gpio_dev->gc.owner = THIS_MODULE; gpio_dev->gc.parent = &pdev->dev; - gpio_dev->gc.ngpio = TOTAL_NUMBER_OF_PINS; + gpio_dev->gc.ngpio = resource_size(res) / 4; #if defined(CONFIG_OF_GPIO) gpio_dev->gc.of_node = pdev->dev.of_node; #endif + gpio_dev->hwbank_num = gpio_dev->gc.ngpio / 64; gpio_dev->groups = kerncz_groups; gpio_dev->ngroups = ARRAY_SIZE(kerncz_groups); @@ -789,7 +794,7 @@ static int amd_gpio_probe(struct platform_device *pdev) return ret; ret = gpiochip_add_pin_range(&gpio_dev->gc, dev_name(&pdev->dev), - 0, 0, TOTAL_NUMBER_OF_PINS); + 0, 0, gpio_dev->gc.ngpio); if (ret) { dev_err(&pdev->dev, "Failed to add pin range\n"); goto out2; @@ -810,7 +815,6 @@ static int amd_gpio_probe(struct platform_device *pdev) &amd_gpio_irqchip, irq_base, amd_gpio_irq_handler); - platform_set_drvdata(pdev, gpio_dev); dev_dbg(&pdev->dev, "amd gpio driver loaded\n"); @@ -829,6 +833,7 @@ static int amd_gpio_remove(struct platform_device *pdev) gpio_dev = platform_get_drvdata(pdev); gpiochip_remove(&gpio_dev->gc); + pinctrl_unregister(gpio_dev->pctrl); return 0; } diff --git a/drivers/pinctrl/pinctrl-amd.h b/drivers/pinctrl/pinctrl-amd.h index 7bfea47dbb47..c03f77822069 100644 --- a/drivers/pinctrl/pinctrl-amd.h +++ b/drivers/pinctrl/pinctrl-amd.h @@ -13,13 +13,12 @@ #ifndef _PINCTRL_AMD_H #define _PINCTRL_AMD_H -#define TOTAL_NUMBER_OF_PINS 192 #define AMD_GPIO_PINS_PER_BANK 64 -#define AMD_GPIO_TOTAL_BANKS 3 #define AMD_GPIO_PINS_BANK0 63 #define AMD_GPIO_PINS_BANK1 64 #define AMD_GPIO_PINS_BANK2 56 +#define AMD_GPIO_PINS_BANK3 32 #define WAKE_INT_MASTER_REG 0xfc #define EOI_MASK (1 << 29) @@ -35,7 +34,9 @@ #define ACTIVE_LEVEL_OFF 9 #define INTERRUPT_ENABLE_OFF 11 #define INTERRUPT_MASK_OFF 12 -#define WAKE_CNTRL_OFF 13 +#define WAKE_CNTRL_OFF_S0I3 13 +#define WAKE_CNTRL_OFF_S3 14 +#define WAKE_CNTRL_OFF_S4 15 #define PIN_STS_OFF 16 #define DRV_STRENGTH_SEL_OFF 17 #define PULL_UP_SEL_OFF 19 @@ -93,6 +94,7 @@ struct amd_gpio { u32 ngroups; struct pinctrl_dev *pctrl; struct gpio_chip gc; + unsigned int hwbank_num; struct resource *res; struct platform_device *pdev; }; From 0e028b49d27caf5476974f4fe421295e65403dae Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Wed, 14 Dec 2016 00:08:27 +0100 Subject: [PATCH 0030/1587] pinctrl: fix DT bindings for marvell,kirkwood-pinctrl On Marvell mv88f6180 mpp pins range from 0 to 19 as well as from 35 to 44. This is already fixed in commit: 9573e7923007961799beff38bc5c5a7635634eef This is the documentation change for above commit. Signed-off-by: Andreas Klinger Signed-off-by: Linus Walleij --- .../pinctrl/marvell,kirkwood-pinctrl.txt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt index 730444a9a4de..6c0ea155b708 100644 --- a/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt @@ -44,16 +44,16 @@ mpp16 16 gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs) mpp17 17 gpio, sdio(d3) mpp18 18 gpo, nand(io0) mpp19 19 gpo, nand(io1) -mpp20 20 gpio, mii(rxerr) -mpp21 21 gpio, audio(spdifi) -mpp22 22 gpio, audio(spdifo) -mpp23 23 gpio, audio(rmclk) -mpp24 24 gpio, audio(bclk) -mpp25 25 gpio, audio(sdo) -mpp26 26 gpio, audio(lrclk) -mpp27 27 gpio, audio(mclk) -mpp28 28 gpio, audio(sdi) -mpp29 29 gpio, audio(extclk) +mpp35 35 gpio, mii(rxerr) +mpp36 36 gpio, audio(spdifi) +mpp37 37 gpio, audio(spdifo) +mpp38 38 gpio, audio(rmclk) +mpp39 39 gpio, audio(bclk) +mpp40 40 gpio, audio(sdo) +mpp41 41 gpio, audio(lrclk) +mpp42 42 gpio, audio(mclk) +mpp43 43 gpio, audio(sdi) +mpp44 44 gpio, audio(extclk) * Marvell Kirkwood 88f6190 From c32c22eea0c47e13cffd6b5f7eedd7a6b6f2c18f Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Wed, 14 Dec 2016 15:24:16 +0100 Subject: [PATCH 0031/1587] pinctrl: stm32: activate strict mux mode This activates strict mode muxing for the STM32 pin controllers, as these do not allow GPIO and functions to use the same pin simultaneously. Signed-off-by: Gabriel Fernandez Acked-by: Patrice Chotard Signed-off-by: Linus Walleij --- drivers/pinctrl/stm32/pinctrl-stm32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index efc43711ff5c..c983a1e33dbe 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -631,6 +631,7 @@ static const struct pinmux_ops stm32_pmx_ops = { .get_function_groups = stm32_pmx_get_func_groups, .set_mux = stm32_pmx_set_mux, .gpio_set_direction = stm32_pmx_gpio_set_direction, + .strict = true, }; /* Pinconf functions */ From 7af355e6715b325d8af29822f4c3dbecd7eeebec Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 20 Dec 2016 06:40:43 +0100 Subject: [PATCH 0032/1587] pinctrl: sirf: atlas7: Add missing 'of_node_put()' Reference to 'sys2pci_np' should be dropped in all cases here, not only in error handling path. Signed-off-by: Christophe JAILLET Signed-off-by: Linus Walleij --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index 7f3041697813..f714f67c4b64 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -5420,14 +5420,15 @@ static int atlas7_pinmux_probe(struct platform_device *pdev) sys2pci_np = of_find_node_by_name(NULL, "sys2pci"); if (!sys2pci_np) return -EINVAL; + ret = of_address_to_resource(sys2pci_np, 0, &res); + of_node_put(sys2pci_np); if (ret) return ret; + pmx->sys2pci_base = devm_ioremap_resource(&pdev->dev, &res); - if (IS_ERR(pmx->sys2pci_base)) { - of_node_put(sys2pci_np); + if (IS_ERR(pmx->sys2pci_base)) return -ENOMEM; - } pmx->dev = &pdev->dev; From 704ae20696128266cf81cf51ecdbeb4c182e9f79 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 20 Dec 2016 06:41:22 +0100 Subject: [PATCH 0033/1587] pinctrl: sirf: atlas7: Improve code layout Add some tab in order to improve indentation. Signed-off-by: Christophe JAILLET Signed-off-by: Linus Walleij --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index f714f67c4b64..76df538fa814 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -5444,7 +5444,7 @@ static int atlas7_pinmux_probe(struct platform_device *pdev) pmx->regs[idx] = of_iomap(np, idx); if (!pmx->regs[idx]) { dev_err(&pdev->dev, - "can't map ioc bank#%d registers\n", idx); + "can't map ioc bank#%d registers\n", idx); ret = -ENOMEM; goto unmap_io; } @@ -6057,8 +6057,8 @@ static int atlas7_gpio_probe(struct platform_device *pdev) ret = gpiochip_add_data(chip, a7gc); if (ret) { dev_err(&pdev->dev, - "%s: error in probe function with status %d\n", - np->name, ret); + "%s: error in probe function with status %d\n", + np->name, ret); goto failed; } From 55e409502e02aeca224efa4cae69d2480879744b Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:55:41 +0100 Subject: [PATCH 0034/1587] pinctrl: update my email address This patch updates my email address as I no longer have access to the old one. Signed-off-by: John Crispin Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/pinctrl-mt7623.c | 2 +- drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h | 2 +- drivers/pinctrl/pinctrl-falcon.c | 2 +- drivers/pinctrl/pinctrl-lantiq.c | 2 +- drivers/pinctrl/pinctrl-lantiq.h | 2 +- drivers/pinctrl/pinctrl-xway.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c index 67895f8234e3..fa28dd6b871b 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7623.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 John Crispin + * Copyright (c) 2016 John Crispin * * 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/pinctrl/mediatek/pinctrl-mtk-mt7623.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h index 3472a76ad422..e06cfc40da0f 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 John Crispin + * Copyright (c) 2016 John Crispin * * 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/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c index 0b0fc2eb48e0..fb73dcbb5ef3 100644 --- a/drivers/pinctrl/pinctrl-falcon.c +++ b/drivers/pinctrl/pinctrl-falcon.c @@ -7,7 +7,7 @@ * by the Free Software Foundation. * * Copyright (C) 2012 Thomas Langer - * Copyright (C) 2012 John Crispin + * Copyright (C) 2012 John Crispin */ #include diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c index a4d647424600..41dc39c7a7b1 100644 --- a/drivers/pinctrl/pinctrl-lantiq.c +++ b/drivers/pinctrl/pinctrl-lantiq.c @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License version 2 as * publishhed by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin + * Copyright (C) 2012 John Crispin */ #include diff --git a/drivers/pinctrl/pinctrl-lantiq.h b/drivers/pinctrl/pinctrl-lantiq.h index e137d139e494..0e4308b8f235 100644 --- a/drivers/pinctrl/pinctrl-lantiq.h +++ b/drivers/pinctrl/pinctrl-lantiq.h @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License version 2 as * publishhed by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin + * Copyright (C) 2012 John Crispin */ #ifndef __PINCTRL_LANTIQ_H diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index dd85ad1807f5..d4167e2c173a 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License version 2 as * publishhed by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin + * Copyright (C) 2012 John Crispin * Copyright (C) 2015 Martin Schiller */ From b1eb8fabc83becdcc3b813f1fe6194f610fe7e9b Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Sun, 25 Dec 2016 02:59:28 +0200 Subject: [PATCH 0035/1587] pinctrl: simplify check for pin request conflicts This is a non-functional change, which deletes code duplication in two of four if-if branches by reordering the checks. Functional identity of the code change can be shown by running through the whole truth table of boolean arguments. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Linus Walleij --- drivers/pinctrl/pinmux.c | 43 ++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index ece702881946..9373146f3afc 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -99,37 +99,24 @@ static int pin_request(struct pinctrl_dev *pctldev, dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", pin, desc->name, owner); - if (gpio_range) { - /* There's no need to support multiple GPIO requests */ - if (desc->gpio_owner) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->gpio_owner, owner); - goto out; - } - if (ops->strict && desc->mux_usecount && - strcmp(desc->mux_owner, owner)) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->mux_owner, owner); - goto out; - } + if ((!gpio_range || ops->strict) && + desc->mux_usecount && strcmp(desc->mux_owner, owner)) { + dev_err(pctldev->dev, + "pin %s already requested by %s; cannot claim for %s\n", + desc->name, desc->mux_owner, owner); + goto out; + } + if ((gpio_range || ops->strict) && desc->gpio_owner) { + dev_err(pctldev->dev, + "pin %s already requested by %s; cannot claim for %s\n", + desc->name, desc->gpio_owner, owner); + goto out; + } + + if (gpio_range) { desc->gpio_owner = owner; } else { - if (desc->mux_usecount && strcmp(desc->mux_owner, owner)) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->mux_owner, owner); - goto out; - } - if (ops->strict && desc->gpio_owner) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->gpio_owner, owner); - goto out; - } - desc->mux_usecount++; if (desc->mux_usecount > 1) return 0; From 059a6e630bb9ee21ff6955d699471bcf2b4b96ab Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 23 Dec 2016 00:47:14 +0000 Subject: [PATCH 0036/1587] pinctrl: single: fix spelling mistakes on "Ivalid" Trivial fixe to spelling mistake "Ivalid" to "Invalid" in dev_err error message. Signed-off-by: Colin Ian King Acked-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-single.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index a5a0392ab817..25edadf75b43 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1134,7 +1134,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, rows = pinctrl_count_index_with_args(np, name); if (rows <= 0) { - dev_err(pcs->dev, "Ivalid number of rows: %d\n", rows); + dev_err(pcs->dev, "Invalid number of rows: %d\n", rows); return -EINVAL; } From b28742be4709929ac6f25ae1f7256e61ed0817a0 Mon Sep 17 00:00:00 2001 From: Gary Bisson Date: Fri, 2 Dec 2016 17:35:18 +0100 Subject: [PATCH 0037/1587] pinctrl: imx: remove const qualifier of imx_pinctrl_soc_info Otherwise can't dynamically update fields such as ngroups which can change over time (with a dt-overlay for instance). Signed-off-by: Gary Bisson Reviewed-by: Fabio Estevam Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx.c | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 5ef7e875b50e..8697c1b7b281 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -42,11 +42,11 @@ struct imx_pinctrl { struct pinctrl_dev *pctl; void __iomem *base; void __iomem *input_sel_base; - const struct imx_pinctrl_soc_info *info; + struct imx_pinctrl_soc_info *info; }; static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name( - const struct imx_pinctrl_soc_info *info, + struct imx_pinctrl_soc_info *info, const char *name) { const struct imx_pin_group *grp = NULL; @@ -65,7 +65,7 @@ static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name( static int imx_get_groups_count(struct pinctrl_dev *pctldev) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; return info->ngroups; } @@ -74,7 +74,7 @@ static const char *imx_get_group_name(struct pinctrl_dev *pctldev, unsigned selector) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; return info->groups[selector].name; } @@ -84,7 +84,7 @@ static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, unsigned *npins) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; if (selector >= info->ngroups) return -EINVAL; @@ -106,7 +106,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **map, unsigned *num_maps) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_group *grp; struct pinctrl_map *new_map; struct device_node *parent; @@ -186,7 +186,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; unsigned int npins, pin_id; int i; @@ -275,7 +275,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, static int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; return info->nfunctions; } @@ -284,7 +284,7 @@ static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev, unsigned selector) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; return info->functions[selector].name; } @@ -294,7 +294,7 @@ static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, unsigned * const num_groups) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; *groups = info->functions[selector].groups; *num_groups = info->functions[selector].num_groups; @@ -306,7 +306,7 @@ static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; struct imx_pin_group *grp; struct imx_pin *imx_pin; @@ -346,7 +346,7 @@ static void imx_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; u32 reg; @@ -371,7 +371,7 @@ static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; u32 reg; @@ -411,7 +411,7 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin_id, unsigned long *config) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; if (pin_reg->conf_reg == -1) { @@ -433,7 +433,7 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev, unsigned num_configs) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; int i; @@ -467,7 +467,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin_id) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; unsigned long config; @@ -484,7 +484,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned group) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; struct imx_pin_group *grp; unsigned long config; const char *name; From a51c158bf0f7cab3bd593586801a1a8b51c7c741 Mon Sep 17 00:00:00 2001 From: Gary Bisson Date: Fri, 2 Dec 2016 17:35:19 +0100 Subject: [PATCH 0038/1587] pinctrl: imx: use radix trees for groups and functions This change is inspired from the pinctrl-single architecture. The problem with current implementation is that it isn't possible to add/remove functions and/or groups dynamically. The radix tree offers an easy way to do so. The intent is to offer a follow-up patch later that will enable the use of pinctrl nodes in dt-overlays. Signed-off-by: Gary Bisson Reviewed-by: Fabio Estevam Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx.c | 164 ++++++++++++++++++++---- drivers/pinctrl/freescale/pinctrl-imx.h | 5 +- 2 files changed, 141 insertions(+), 28 deletions(-) diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 8697c1b7b281..e832a2c7af68 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -53,10 +53,9 @@ static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name( int i; for (i = 0; i < info->ngroups; i++) { - if (!strcmp(info->groups[i].name, name)) { - grp = &info->groups[i]; + grp = radix_tree_lookup(&info->pgtree, i); + if (grp && !strcmp(grp->name, name)) break; - } } return grp; @@ -75,8 +74,13 @@ static const char *imx_get_group_name(struct pinctrl_dev *pctldev, { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pin_group *grp = NULL; - return info->groups[selector].name; + grp = radix_tree_lookup(&info->pgtree, selector); + if (!grp) + return NULL; + + return grp->name; } static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, @@ -85,12 +89,17 @@ static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pin_group *grp = NULL; if (selector >= info->ngroups) return -EINVAL; - *pins = info->groups[selector].pin_ids; - *npins = info->groups[selector].npins; + grp = radix_tree_lookup(&info->pgtree, selector); + if (!grp) + return -EINVAL; + + *pins = grp->pin_ids; + *npins = grp->npins; return 0; } @@ -190,17 +199,25 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, const struct imx_pin_reg *pin_reg; unsigned int npins, pin_id; int i; - struct imx_pin_group *grp; + struct imx_pin_group *grp = NULL; + struct imx_pmx_func *func = NULL; /* * Configure the mux mode for each pin in the group for a specific * function. */ - grp = &info->groups[group]; + grp = radix_tree_lookup(&info->pgtree, group); + if (!grp) + return -EINVAL; + + func = radix_tree_lookup(&info->ftree, selector); + if (!func) + return -EINVAL; + npins = grp->npins; dev_dbg(ipctl->dev, "enable function %s group %s\n", - info->functions[selector].name, grp->name); + func->name, grp->name); for (i = 0; i < npins; i++) { struct imx_pin *pin = &grp->pins[i]; @@ -285,8 +302,13 @@ static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev, { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pmx_func *func = NULL; - return info->functions[selector].name; + func = radix_tree_lookup(&info->ftree, selector); + if (!func) + return NULL; + + return func->name; } static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, @@ -295,9 +317,14 @@ static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pmx_func *func = NULL; - *groups = info->functions[selector].groups; - *num_groups = info->functions[selector].num_groups; + func = radix_tree_lookup(&info->ftree, selector); + if (!func) + return -EINVAL; + + *groups = func->groups; + *num_groups = func->num_groups; return 0; } @@ -323,7 +350,9 @@ static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, /* Find the pinctrl config with GPIO mux mode for the requested pin */ for (group = 0; group < info->ngroups; group++) { - grp = &info->groups[group]; + grp = radix_tree_lookup(&info->pgtree, group); + if (!grp) + continue; for (pin = 0; pin < grp->npins; pin++) { imx_pin = &grp->pins[pin]; if (imx_pin->pin == offset && !imx_pin->mux_mode) @@ -494,7 +523,10 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, return; seq_printf(s, "\n"); - grp = &info->groups[group]; + grp = radix_tree_lookup(&info->pgtree, group); + if (!grp) + return; + for (i = 0; i < grp->npins; i++) { struct imx_pin *pin = &grp->pins[i]; name = pin_get_name(pctldev, pin->pin); @@ -614,7 +646,9 @@ static int imx_pinctrl_parse_functions(struct device_node *np, dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); - func = &info->functions[index]; + func = radix_tree_lookup(&info->ftree, index); + if (!func) + return -EINVAL; /* Initialise function */ func->name = np->name; @@ -628,7 +662,16 @@ static int imx_pinctrl_parse_functions(struct device_node *np, for_each_child_of_node(np, child) { func->groups[i] = child->name; - grp = &info->groups[info->group_index++]; + + grp = devm_kzalloc(info->dev, sizeof(struct imx_pin_group), + GFP_KERNEL); + if (!grp) + return -ENOMEM; + + mutex_lock(&info->mutex); + radix_tree_insert(&info->pgtree, info->group_index++, grp); + mutex_unlock(&info->mutex); + imx_pinctrl_parse_groups(child, grp, info, i++); } @@ -681,11 +724,19 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, } } - info->nfunctions = nfuncs; - info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func), + for (i = 0; i < nfuncs; i++) { + struct imx_pmx_func *function; + + function = devm_kzalloc(&pdev->dev, sizeof(*function), GFP_KERNEL); - if (!info->functions) - return -ENOMEM; + if (!function) + return -ENOMEM; + + mutex_lock(&info->mutex); + radix_tree_insert(&info->ftree, i, function); + mutex_unlock(&info->mutex); + } + info->nfunctions = nfuncs; info->group_index = 0; if (flat_funcs) { @@ -695,14 +746,11 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, for_each_child_of_node(np, child) info->ngroups += of_get_child_count(child); } - info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group), - GFP_KERNEL); - if (!info->groups) - return -ENOMEM; if (flat_funcs) { imx_pinctrl_parse_functions(np, info, 0); } else { + i = 0; for_each_child_of_node(np, child) imx_pinctrl_parse_functions(child, info, i++); } @@ -710,6 +758,59 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, return 0; } +/* + * imx_free_funcs() - free memory used by functions + * @info: info driver instance + */ +static void imx_free_funcs(struct imx_pinctrl_soc_info *info) +{ + int i; + + mutex_lock(&info->mutex); + for (i = 0; i < info->nfunctions; i++) { + struct imx_pmx_func *func; + + func = radix_tree_lookup(&info->ftree, i); + if (!func) + continue; + radix_tree_delete(&info->ftree, i); + } + mutex_unlock(&info->mutex); +} + +/* + * imx_free_pingroups() - free memory used by pingroups + * @info: info driver instance + */ +static void imx_free_pingroups(struct imx_pinctrl_soc_info *info) +{ + int i; + + mutex_lock(&info->mutex); + for (i = 0; i < info->ngroups; i++) { + struct imx_pin_group *pingroup; + + pingroup = radix_tree_lookup(&info->pgtree, i); + if (!pingroup) + continue; + radix_tree_delete(&info->pgtree, i); + } + mutex_unlock(&info->mutex); +} + +/* + * imx_free_resources() - free memory used by this driver + * @info: info driver instance + */ +static void imx_free_resources(struct imx_pinctrl *ipctl) +{ + if (ipctl->pctl) + pinctrl_unregister(ipctl->pctl); + + imx_free_funcs(ipctl->info); + imx_free_pingroups(ipctl->info); +} + int imx_pinctrl_probe(struct platform_device *pdev, struct imx_pinctrl_soc_info *info) { @@ -783,10 +884,15 @@ int imx_pinctrl_probe(struct platform_device *pdev, imx_pinctrl_desc->confops = &imx_pinconf_ops; imx_pinctrl_desc->owner = THIS_MODULE; + mutex_init(&info->mutex); + + INIT_RADIX_TREE(&info->pgtree, GFP_KERNEL); + INIT_RADIX_TREE(&info->ftree, GFP_KERNEL); + ret = imx_pinctrl_probe_dt(pdev, info); if (ret) { dev_err(&pdev->dev, "fail to probe dt properties\n"); - return ret; + goto free; } ipctl->info = info; @@ -796,10 +902,16 @@ int imx_pinctrl_probe(struct platform_device *pdev, imx_pinctrl_desc, ipctl); if (IS_ERR(ipctl->pctl)) { dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); - return PTR_ERR(ipctl->pctl); + ret = PTR_ERR(ipctl->pctl); + goto free; } dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); return 0; + +free: + imx_free_resources(ipctl); + + return ret; } diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index 8af8aa2897ab..62aa8f8f57e9 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -76,13 +76,14 @@ struct imx_pinctrl_soc_info { const struct pinctrl_pin_desc *pins; unsigned int npins; struct imx_pin_reg *pin_regs; - struct imx_pin_group *groups; unsigned int ngroups; unsigned int group_index; - struct imx_pmx_func *functions; unsigned int nfunctions; unsigned int flags; const char *gpr_compatible; + struct radix_tree_root ftree; + struct radix_tree_root pgtree; + struct mutex mutex; }; #define SHARE_MUX_CONF_REG 0x1 From 279e4af7b4bebc6a5bf2d0e5b3209f3dcea94a19 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 30 Dec 2016 15:30:00 +0900 Subject: [PATCH 0039/1587] spi: bcm-qspi: Enable the driver on BMIPS_GENERIC The Broadcom BCM7XXX ARM and MIPS based SoCs share a similar hardware block for SPI. Signed-off-by: Jaedon Shin Acked-by: Florian Fainelli Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ec4aa252d6e8..c982a01022ba 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -162,7 +162,8 @@ config SPI_BCM63XX_HSSPI config SPI_BCM_QSPI tristate "Broadcom BSPI and MSPI controller support" - depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST + depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || \ + BMIPS_GENERIC || COMPILE_TEST default ARCH_BCM_IPROC help Enables support for the Broadcom SPI flash and MSPI controller. From 78d759daceaf0a7058f37c4142bdca9948b6d987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 29 Dec 2016 17:27:55 +0100 Subject: [PATCH 0040/1587] spi: bcm53xx: set of_node to let DT specify device(s) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting of_node of master's dev seems to be a common way of letting it work nicely with DT. This allows specifying device there instead of hardcoding one in the driver code. This was successfully tested with commit 1b47b98acce2 ("ARM: BCM5301X: Add DT entry for SPI controller and NOR flash") Signed-off-by: Rafał Miłecki Signed-off-by: Mark Brown --- drivers/spi/spi-bcm53xx.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c index afb51699dbb5..0c61ad4edb1a 100644 --- a/drivers/spi/spi-bcm53xx.c +++ b/drivers/spi/spi-bcm53xx.c @@ -275,10 +275,6 @@ static int bcm53xxspi_flash_read(struct spi_device *spi, * BCMA **************************************************/ -static struct spi_board_info bcm53xx_info = { - .modalias = "bcm53xxspiflash", -}; - static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS), {}, @@ -311,6 +307,7 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core) b53spi->bspi = true; bcm53xxspi_disable_bspi(b53spi); + master->dev.of_node = dev->of_node; master->transfer_one = bcm53xxspi_transfer_one; if (b53spi->mmio_base) master->spi_flash_read = bcm53xxspi_flash_read; @@ -324,9 +321,6 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core) return err; } - /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */ - spi_new_device(master, &bcm53xx_info); - return 0; } From cfd6693c06324174ceeac7aed570a0df67db7c4f Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 21 Dec 2016 11:10:30 +0100 Subject: [PATCH 0041/1587] spi: armada-3700: Replaced raw values for nbits by the SPI macros Currently, function a3700_spi_pin_mode_set() configures the SPI transfer mode according to the value passed as second argument. This value is detected using the raw values from a switch case. This commit replaces these raw values by the corresponding macro constants in linux/spi/spi.h Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 4e68f34957cc..9bee56ddff39 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -170,12 +170,12 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi, val &= ~(A3700_SPI_DATA_PIN0 | A3700_SPI_DATA_PIN1); switch (pin_mode) { - case 1: + case SPI_NBITS_SINGLE: break; - case 2: + case SPI_NBITS_DUAL: val |= A3700_SPI_DATA_PIN0; break; - case 4: + case SPI_NBITS_QUAD: val |= A3700_SPI_DATA_PIN1; break; default: From 85798e153e6c3834ab2d69ee9d4db7d85f13809d Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 21 Dec 2016 11:10:29 +0100 Subject: [PATCH 0042/1587] spi: armada-3700: Coding style fixes The following warning are reported by checkpatch.pl: CHECK: Alignment should match open parenthesis +static void a3700_spi_transfer_setup(struct spi_device *spi, + struct spi_transfer *xfer) WARNING: Missing a blank line after declarations + u32 data = le32_to_cpu(val); + memcpy(a3700_spi->rx_buf, &data, 4); total: 0 errors, 1 warnings, 1 checks, 923 lines checked Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 9bee56ddff39..0baa69325e78 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -420,7 +420,7 @@ static void a3700_spi_fifo_thres_set(struct a3700_spi *a3700_spi, } static void a3700_spi_transfer_setup(struct spi_device *spi, - struct spi_transfer *xfer) + struct spi_transfer *xfer) { struct a3700_spi *a3700_spi; unsigned int byte_len; @@ -561,6 +561,7 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi) val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG); if (a3700_spi->buf_len >= 4) { u32 data = le32_to_cpu(val); + memcpy(a3700_spi->rx_buf, &data, 4); a3700_spi->buf_len -= 4; From 54475f531bb8d7078f63c159e5e0615d486c498c Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:44 -0800 Subject: [PATCH 0043/1587] fscrypt: use ENOKEY when file cannot be created w/o key As part of an effort to clean up fscrypt-related error codes, make attempting to create a file in an encrypted directory that hasn't been "unlocked" fail with ENOKEY. Previously, several error codes were used for this case, including ENOENT, EACCES, and EPERM, and they were not consistent between and within filesystems. ENOKEY is a better choice because it expresses that the failure is due to lacking the encryption key. It also matches the error code returned when trying to open an encrypted regular file without the key. I am not aware of any users who might be relying on the previous inconsistent error codes, which were never documented anywhere. This failure case will be exercised by an xfstest. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/fname.c | 4 ++-- fs/ext4/ialloc.c | 2 +- fs/ext4/namei.c | 4 +++- fs/f2fs/dir.c | 5 ++++- fs/f2fs/namei.c | 4 ++-- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 56ad9d195f18..13052b85c393 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -332,7 +332,7 @@ int fscrypt_fname_usr_to_disk(struct inode *inode, * in a directory. Consequently, a user space name cannot be mapped to * a disk-space name */ - return -EACCES; + return -ENOKEY; } EXPORT_SYMBOL(fscrypt_fname_usr_to_disk); @@ -367,7 +367,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return 0; } if (!lookup) - return -EACCES; + return -ENOKEY; /* * We don't have the key and we are doing a lookup; decode the diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index e57e8d90ea54..f372fc431b8e 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -771,7 +771,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, if (err) return ERR_PTR(err); if (!fscrypt_has_encryption_key(dir)) - return ERR_PTR(-EPERM); + return ERR_PTR(-ENOKEY); if (!handle) nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb); encrypt = 1; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index eadba919f26b..80b8afa4a8f9 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1378,6 +1378,8 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, return NULL; retval = ext4_fname_setup_filename(dir, d_name, 1, &fname); + if (retval == -ENOENT) + return NULL; if (retval) return ERR_PTR(retval); @@ -3088,7 +3090,7 @@ static int ext4_symlink(struct inode *dir, if (err) return err; if (!fscrypt_has_encryption_key(dir)) - return -EPERM; + return -ENOKEY; disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + sizeof(struct fscrypt_symlink_data)); sd = kzalloc(disk_link.len, GFP_KERNEL); diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 827c5daef4fc..18607fc5240d 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -268,7 +268,10 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, err = fscrypt_setup_filename(dir, child, 1, &fname); if (err) { - *res_page = ERR_PTR(err); + if (err == -ENOENT) + *res_page = NULL; + else + *res_page = ERR_PTR(err); return NULL; } diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 56c19b0610a8..11cabcadb1a3 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -403,7 +403,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, return err; if (!fscrypt_has_encryption_key(dir)) - return -EPERM; + return -ENOKEY; disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + sizeof(struct fscrypt_symlink_data)); @@ -447,7 +447,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, goto err_out; if (!fscrypt_has_encryption_key(inode)) { - err = -EPERM; + err = -ENOKEY; goto err_out; } From dffd0cfa06d4ed83bb3ae8eb067989ceec5d18e1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:45 -0800 Subject: [PATCH 0044/1587] fscrypt: use ENOTDIR when setting encryption policy on nondirectory As part of an effort to clean up fscrypt-related error codes, make FS_IOC_SET_ENCRYPTION_POLICY fail with ENOTDIR when the file descriptor does not refer to a directory. This is more descriptive than EINVAL, which was ambiguous with some of the other error cases. I am not aware of any users who might be relying on the previous error code of EINVAL, which was never documented anywhere, and in some buggy kernels did not exist at all as the S_ISDIR() check was missing. This failure case will be exercised by an xfstest. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index d6cd7ea4851d..40ecd7173e34 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -116,7 +116,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) if (!inode_has_encryption_context(inode)) { if (!S_ISDIR(inode->i_mode)) - ret = -EINVAL; + ret = -ENOTDIR; else if (!inode->i_sb->s_cop->empty_dir) ret = -EOPNOTSUPP; else if (!inode->i_sb->s_cop->empty_dir(inode)) From 8488cd96ff88966ccb076e4f3654f59d84ba686d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:46 -0800 Subject: [PATCH 0045/1587] fscrypt: use EEXIST when file already uses different policy As part of an effort to clean up fscrypt-related error codes, make FS_IOC_SET_ENCRYPTION_POLICY fail with EEXIST when the file already uses a different encryption policy. This is more descriptive than EINVAL, which was ambiguous with some of the other error cases. I am not aware of any users who might be relying on the previous error code of EINVAL, which was never documented anywhere. This failure case will be exercised by an xfstest. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 40ecd7173e34..47f19800ceb7 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -129,7 +129,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n", __func__); - ret = -EINVAL; + ret = -EEXIST; } inode_unlock(inode); From 868e1bc64d04294b76f1c0eedb79e0742be441c7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:47 -0800 Subject: [PATCH 0046/1587] fscrypt: remove user-triggerable warning messages Several warning messages were not rate limited and were user-triggerable from FS_IOC_SET_ENCRYPTION_POLICY. These shouldn't really have been there in the first place, but either way they aren't as useful now that the error codes have been improved. So just remove them. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/policy.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 47f19800ceb7..521b182dd902 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -66,20 +66,12 @@ static int create_encryption_context_from_policy(struct inode *inode, FS_KEY_DESCRIPTOR_SIZE); if (!fscrypt_valid_contents_enc_mode( - policy->contents_encryption_mode)) { - printk(KERN_WARNING - "%s: Invalid contents encryption mode %d\n", __func__, - policy->contents_encryption_mode); + policy->contents_encryption_mode)) return -EINVAL; - } if (!fscrypt_valid_filenames_enc_mode( - policy->filenames_encryption_mode)) { - printk(KERN_WARNING - "%s: Invalid filenames encryption mode %d\n", __func__, - policy->filenames_encryption_mode); + policy->filenames_encryption_mode)) return -EINVAL; - } if (policy->flags & ~FS_POLICY_FLAGS_VALID) return -EINVAL; @@ -126,9 +118,6 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) &policy); } else if (!is_encryption_context_consistent_with_policy(inode, &policy)) { - printk(KERN_WARNING - "%s: Policy inconsistent with encryption context\n", - __func__); ret = -EEXIST; } From efee590e4a3fa7b66f78aa06eff33f59570ca96d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:48 -0800 Subject: [PATCH 0047/1587] fscrypt: pass up error codes from ->get_context() It was possible for the ->get_context() operation to fail with a specific error code, which was then not returned to the caller of FS_IOC_SET_ENCRYPTION_POLICY or FS_IOC_GET_ENCRYPTION_POLICY. Make sure to pass through these error codes. Also reorganize the code so that ->get_context() only needs to be called one time when setting an encryption policy, and handle contexts of unrecognized sizes more appropriately. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/policy.c | 54 ++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 521b182dd902..4c99972899c7 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -13,37 +13,20 @@ #include #include "fscrypt_private.h" -static int inode_has_encryption_context(struct inode *inode) -{ - if (!inode->i_sb->s_cop->get_context) - return 0; - return (inode->i_sb->s_cop->get_context(inode, NULL, 0L) > 0); -} - /* - * check whether the policy is consistent with the encryption context - * for the inode + * check whether an encryption policy is consistent with an encryption context */ -static int is_encryption_context_consistent_with_policy(struct inode *inode, +static bool is_encryption_context_consistent_with_policy( + const struct fscrypt_context *ctx, const struct fscrypt_policy *policy) { - struct fscrypt_context ctx; - int res; - - if (!inode->i_sb->s_cop->get_context) - return 0; - - res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); - if (res != sizeof(ctx)) - return 0; - - return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor, - FS_KEY_DESCRIPTOR_SIZE) == 0 && - (ctx.flags == policy->flags) && - (ctx.contents_encryption_mode == - policy->contents_encryption_mode) && - (ctx.filenames_encryption_mode == - policy->filenames_encryption_mode)); + return memcmp(ctx->master_key_descriptor, policy->master_key_descriptor, + FS_KEY_DESCRIPTOR_SIZE) == 0 && + (ctx->flags == policy->flags) && + (ctx->contents_encryption_mode == + policy->contents_encryption_mode) && + (ctx->filenames_encryption_mode == + policy->filenames_encryption_mode); } static int create_encryption_context_from_policy(struct inode *inode, @@ -90,6 +73,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) struct fscrypt_policy policy; struct inode *inode = file_inode(filp); int ret; + struct fscrypt_context ctx; if (copy_from_user(&policy, arg, sizeof(policy))) return -EFAULT; @@ -106,7 +90,8 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) inode_lock(inode); - if (!inode_has_encryption_context(inode)) { + ret = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (ret == -ENODATA) { if (!S_ISDIR(inode->i_mode)) ret = -ENOTDIR; else if (!inode->i_sb->s_cop->empty_dir) @@ -116,8 +101,13 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) else ret = create_encryption_context_from_policy(inode, &policy); - } else if (!is_encryption_context_consistent_with_policy(inode, - &policy)) { + } else if (ret == sizeof(ctx) && + is_encryption_context_consistent_with_policy(&ctx, + &policy)) { + /* The file already uses the same encryption policy. */ + ret = 0; + } else if (ret >= 0 || ret == -ERANGE) { + /* The file already uses a different encryption policy. */ ret = -EEXIST; } @@ -140,8 +130,10 @@ int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg) return -ENODATA; res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (res < 0 && res != -ERANGE) + return res; if (res != sizeof(ctx)) - return -ENODATA; + return -EINVAL; if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) return -EINVAL; From 58ae74683ae2c07cd717a91799edb50231061938 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 19 Dec 2016 12:25:32 +0100 Subject: [PATCH 0048/1587] fscrypt: factor out bio specific functions That way we can get rid of the direct dependency on CONFIG_BLOCK. Fixes: d475a507457b ("ubifs: Add skeleton for fscrypto") Reported-by: Arnd Bergmann Reported-by: Randy Dunlap Reviewed-by: Eric Biggers Reviewed-by: Christoph Hellwig Reviewed-by: David Gstir Signed-off-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/Kconfig | 1 - fs/crypto/Makefile | 1 + fs/crypto/bio.c | 145 +++++++++++++++++++++++++++++++++ fs/crypto/crypto.c | 157 ++++-------------------------------- fs/crypto/fscrypt_private.h | 16 +++- include/linux/fscrypto.h | 11 ++- 6 files changed, 184 insertions(+), 147 deletions(-) create mode 100644 fs/crypto/bio.c diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig index f514978f6688..08b46e6e3995 100644 --- a/fs/crypto/Kconfig +++ b/fs/crypto/Kconfig @@ -1,6 +1,5 @@ config FS_ENCRYPTION tristate "FS Encryption (Per-file encryption)" - depends on BLOCK select CRYPTO select CRYPTO_AES select CRYPTO_CBC diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index f17684c48739..9f6607f17b53 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o fscrypto-y := crypto.o fname.o policy.o keyinfo.o +fscrypto-$(CONFIG_BLOCK) += bio.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c new file mode 100644 index 000000000000..a409a84f1bca --- /dev/null +++ b/fs/crypto/bio.c @@ -0,0 +1,145 @@ +/* + * This contains encryption functions for per-file encryption. + * + * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2015, Motorola Mobility + * + * Written by Michael Halcrow, 2014. + * + * Filename encryption additions + * Uday Savagaonkar, 2014 + * Encryption policy handling additions + * Ildar Muslukhov, 2014 + * Add fscrypt_pullback_bio_page() + * Jaegeuk Kim, 2015. + * + * This has not yet undergone a rigorous security audit. + * + * The usage of AES-XTS should conform to recommendations in NIST + * Special Publication 800-38E and IEEE P1619/D16. + */ + +#include +#include +#include +#include +#include "fscrypt_private.h" + +/* + * Call fscrypt_decrypt_page on every single page, reusing the encryption + * context. + */ +static void completion_pages(struct work_struct *work) +{ + struct fscrypt_ctx *ctx = + container_of(work, struct fscrypt_ctx, r.work); + struct bio *bio = ctx->r.bio; + struct bio_vec *bv; + int i; + + bio_for_each_segment_all(bv, bio, i) { + struct page *page = bv->bv_page; + int ret = fscrypt_decrypt_page(page->mapping->host, page, + PAGE_SIZE, 0, page->index); + + if (ret) { + WARN_ON_ONCE(1); + SetPageError(page); + } else { + SetPageUptodate(page); + } + unlock_page(page); + } + fscrypt_release_ctx(ctx); + bio_put(bio); +} + +void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio) +{ + INIT_WORK(&ctx->r.work, completion_pages); + ctx->r.bio = bio; + queue_work(fscrypt_read_workqueue, &ctx->r.work); +} +EXPORT_SYMBOL(fscrypt_decrypt_bio_pages); + +void fscrypt_pullback_bio_page(struct page **page, bool restore) +{ + struct fscrypt_ctx *ctx; + struct page *bounce_page; + + /* The bounce data pages are unmapped. */ + if ((*page)->mapping) + return; + + /* The bounce data page is unmapped. */ + bounce_page = *page; + ctx = (struct fscrypt_ctx *)page_private(bounce_page); + + /* restore control page */ + *page = ctx->w.control_page; + + if (restore) + fscrypt_restore_control_page(bounce_page); +} +EXPORT_SYMBOL(fscrypt_pullback_bio_page); + +int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, + sector_t pblk, unsigned int len) +{ + struct fscrypt_ctx *ctx; + struct page *ciphertext_page = NULL; + struct bio *bio; + int ret, err = 0; + + BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); + + ctx = fscrypt_get_ctx(inode, GFP_NOFS); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ciphertext_page = fscrypt_alloc_bounce_page(ctx, GFP_NOWAIT); + if (IS_ERR(ciphertext_page)) { + err = PTR_ERR(ciphertext_page); + goto errout; + } + + while (len--) { + err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk, + ZERO_PAGE(0), ciphertext_page, + PAGE_SIZE, 0, GFP_NOFS); + if (err) + goto errout; + + bio = bio_alloc(GFP_NOWAIT, 1); + if (!bio) { + err = -ENOMEM; + goto errout; + } + bio->bi_bdev = inode->i_sb->s_bdev; + bio->bi_iter.bi_sector = + pblk << (inode->i_sb->s_blocksize_bits - 9); + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + ret = bio_add_page(bio, ciphertext_page, + inode->i_sb->s_blocksize, 0); + if (ret != inode->i_sb->s_blocksize) { + /* should never happen! */ + WARN_ON(1); + bio_put(bio); + err = -EIO; + goto errout; + } + err = submit_bio_wait(bio); + if ((err == 0) && bio->bi_error) + err = -EIO; + bio_put(bio); + if (err) + goto errout; + lblk++; + pblk++; + } + err = 0; +errout: + fscrypt_release_ctx(ctx); + return err; +} +EXPORT_SYMBOL(fscrypt_zeroout_range); diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index ac8e4f6a3773..02a7a9286449 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include "fscrypt_private.h" @@ -44,7 +43,7 @@ static mempool_t *fscrypt_bounce_page_pool = NULL; static LIST_HEAD(fscrypt_free_ctxs); static DEFINE_SPINLOCK(fscrypt_ctx_lock); -static struct workqueue_struct *fscrypt_read_workqueue; +struct workqueue_struct *fscrypt_read_workqueue; static DEFINE_MUTEX(fscrypt_init_mutex); static struct kmem_cache *fscrypt_ctx_cachep; @@ -141,16 +140,10 @@ static void page_crypt_complete(struct crypto_async_request *req, int res) complete(&ecr->completion); } -typedef enum { - FS_DECRYPT = 0, - FS_ENCRYPT, -} fscrypt_direction_t; - -static int do_page_crypto(const struct inode *inode, - fscrypt_direction_t rw, u64 lblk_num, - struct page *src_page, struct page *dest_page, - unsigned int len, unsigned int offs, - gfp_t gfp_flags) +int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw, + u64 lblk_num, struct page *src_page, + struct page *dest_page, unsigned int len, + unsigned int offs, gfp_t gfp_flags) { struct { __le64 index; @@ -205,7 +198,8 @@ static int do_page_crypto(const struct inode *inode, return 0; } -static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) +struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, + gfp_t gfp_flags) { ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags); if (ctx->w.bounce_page == NULL) @@ -260,9 +254,9 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) { /* with inplace-encryption we just encrypt the page */ - err = do_page_crypto(inode, FS_ENCRYPT, lblk_num, - page, ciphertext_page, - len, offs, gfp_flags); + err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, page, + ciphertext_page, len, offs, + gfp_flags); if (err) return ERR_PTR(err); @@ -276,14 +270,14 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, return (struct page *)ctx; /* The encryption operation will require a bounce page. */ - ciphertext_page = alloc_bounce_page(ctx, gfp_flags); + ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags); if (IS_ERR(ciphertext_page)) goto errout; ctx->w.control_page = page; - err = do_page_crypto(inode, FS_ENCRYPT, lblk_num, - page, ciphertext_page, - len, offs, gfp_flags); + err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, + page, ciphertext_page, len, offs, + gfp_flags); if (err) { ciphertext_page = ERR_PTR(err); goto errout; @@ -320,72 +314,11 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page, if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES)) BUG_ON(!PageLocked(page)); - return do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page, len, - offs, GFP_NOFS); + return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page, + len, offs, GFP_NOFS); } EXPORT_SYMBOL(fscrypt_decrypt_page); -int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, - sector_t pblk, unsigned int len) -{ - struct fscrypt_ctx *ctx; - struct page *ciphertext_page = NULL; - struct bio *bio; - int ret, err = 0; - - BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); - - ctx = fscrypt_get_ctx(inode, GFP_NOFS); - if (IS_ERR(ctx)) - return PTR_ERR(ctx); - - ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT); - if (IS_ERR(ciphertext_page)) { - err = PTR_ERR(ciphertext_page); - goto errout; - } - - while (len--) { - err = do_page_crypto(inode, FS_ENCRYPT, lblk, - ZERO_PAGE(0), ciphertext_page, - PAGE_SIZE, 0, GFP_NOFS); - if (err) - goto errout; - - bio = bio_alloc(GFP_NOWAIT, 1); - if (!bio) { - err = -ENOMEM; - goto errout; - } - bio->bi_bdev = inode->i_sb->s_bdev; - bio->bi_iter.bi_sector = - pblk << (inode->i_sb->s_blocksize_bits - 9); - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - ret = bio_add_page(bio, ciphertext_page, - inode->i_sb->s_blocksize, 0); - if (ret != inode->i_sb->s_blocksize) { - /* should never happen! */ - WARN_ON(1); - bio_put(bio); - err = -EIO; - goto errout; - } - err = submit_bio_wait(bio); - if ((err == 0) && bio->bi_error) - err = -EIO; - bio_put(bio); - if (err) - goto errout; - lblk++; - pblk++; - } - err = 0; -errout: - fscrypt_release_ctx(ctx); - return err; -} -EXPORT_SYMBOL(fscrypt_zeroout_range); - /* * Validate dentries for encrypted directories to make sure we aren't * potentially caching stale data after a key has been added or @@ -442,64 +375,6 @@ const struct dentry_operations fscrypt_d_ops = { }; EXPORT_SYMBOL(fscrypt_d_ops); -/* - * Call fscrypt_decrypt_page on every single page, reusing the encryption - * context. - */ -static void completion_pages(struct work_struct *work) -{ - struct fscrypt_ctx *ctx = - container_of(work, struct fscrypt_ctx, r.work); - struct bio *bio = ctx->r.bio; - struct bio_vec *bv; - int i; - - bio_for_each_segment_all(bv, bio, i) { - struct page *page = bv->bv_page; - int ret = fscrypt_decrypt_page(page->mapping->host, page, - PAGE_SIZE, 0, page->index); - - if (ret) { - WARN_ON_ONCE(1); - SetPageError(page); - } else { - SetPageUptodate(page); - } - unlock_page(page); - } - fscrypt_release_ctx(ctx); - bio_put(bio); -} - -void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio) -{ - INIT_WORK(&ctx->r.work, completion_pages); - ctx->r.bio = bio; - queue_work(fscrypt_read_workqueue, &ctx->r.work); -} -EXPORT_SYMBOL(fscrypt_decrypt_bio_pages); - -void fscrypt_pullback_bio_page(struct page **page, bool restore) -{ - struct fscrypt_ctx *ctx; - struct page *bounce_page; - - /* The bounce data pages are unmapped. */ - if ((*page)->mapping) - return; - - /* The bounce data page is unmapped. */ - bounce_page = *page; - ctx = (struct fscrypt_ctx *)page_private(bounce_page); - - /* restore control page */ - *page = ctx->w.control_page; - - if (restore) - fscrypt_restore_control_page(bounce_page); -} -EXPORT_SYMBOL(fscrypt_pullback_bio_page); - void fscrypt_restore_control_page(struct page *page) { struct fscrypt_ctx *ctx; diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index aeab032d7d35..7bff7b4c7498 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -71,6 +71,11 @@ struct fscrypt_info { u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE]; }; +typedef enum { + FS_DECRYPT = 0, + FS_ENCRYPT, +} fscrypt_direction_t; + #define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 #define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002 @@ -85,7 +90,16 @@ struct fscrypt_completion_result { /* crypto.c */ -int fscrypt_initialize(unsigned int cop_flags); +extern int fscrypt_initialize(unsigned int cop_flags); +extern struct workqueue_struct *fscrypt_read_workqueue; +extern int fscrypt_do_page_crypto(const struct inode *inode, + fscrypt_direction_t rw, u64 lblk_num, + struct page *src_page, + struct page *dest_page, + unsigned int len, unsigned int offs, + gfp_t gfp_flags); +extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, + gfp_t gfp_flags); /* keyinfo.c */ extern int fscrypt_get_crypt_info(struct inode *); diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index c074b670aa99..2a2815702095 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -174,11 +174,8 @@ extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, u64, gfp_t); extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, unsigned int, u64); -extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); -extern void fscrypt_pullback_bio_page(struct page **, bool); extern void fscrypt_restore_control_page(struct page *); -extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, - unsigned int); + /* policy.c */ extern int fscrypt_ioctl_set_policy(struct file *, const void __user *); extern int fscrypt_ioctl_get_policy(struct file *, void __user *); @@ -201,6 +198,12 @@ extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, const struct fscrypt_str *, struct fscrypt_str *); extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, struct fscrypt_str *); + +/* bio.c */ +extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); +extern void fscrypt_pullback_bio_page(struct page **, bool); +extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, + unsigned int); #endif /* crypto.c */ From adc064cd9f6ee7a8b426955e6a28191abc9d0e8e Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Thu, 15 Dec 2016 08:57:51 -0800 Subject: [PATCH 0049/1587] dmaengine: Convert ID allocation to an IDA dmaengine currently uses an IDR to allocate DMA IDs, but it only needs to know whether IDs are in use or not; the ID to pointer functionality of the IDR is unused. That means it can use the more space-efficient IDA. Signed-off-by: Matthew Wilcox Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 6b535262ac5d..24e0221fd66d 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -65,7 +65,7 @@ #include static DEFINE_MUTEX(dma_list_mutex); -static DEFINE_IDR(dma_idr); +static DEFINE_IDA(dma_ida); static LIST_HEAD(dma_device_list); static long dmaengine_ref_count; @@ -162,7 +162,7 @@ static void chan_dev_release(struct device *dev) chan_dev = container_of(dev, typeof(*chan_dev), device); if (atomic_dec_and_test(chan_dev->idr_ref)) { mutex_lock(&dma_list_mutex); - idr_remove(&dma_idr, chan_dev->dev_id); + ida_remove(&dma_ida, chan_dev->dev_id); mutex_unlock(&dma_list_mutex); kfree(chan_dev->idr_ref); } @@ -898,14 +898,15 @@ static int get_dma_id(struct dma_device *device) { int rc; - mutex_lock(&dma_list_mutex); + do { + if (!ida_pre_get(&dma_ida, GFP_KERNEL)) + return -ENOMEM; + mutex_lock(&dma_list_mutex); + rc = ida_get_new(&dma_ida, &device->dev_id); + mutex_unlock(&dma_list_mutex); + } while (rc == -EAGAIN); - rc = idr_alloc(&dma_idr, NULL, 0, 0, GFP_KERNEL); - if (rc >= 0) - device->dev_id = rc; - - mutex_unlock(&dma_list_mutex); - return rc < 0 ? rc : 0; + return rc; } /** @@ -1035,7 +1036,7 @@ err_out: /* if we never registered a channel just release the idr */ if (atomic_read(idr_ref) == 0) { mutex_lock(&dma_list_mutex); - idr_remove(&dma_idr, device->dev_id); + ida_remove(&dma_ida, device->dev_id); mutex_unlock(&dma_list_mutex); kfree(idr_ref); return rc; From c4c5cd695fdeab96584b850415beb355f1509c19 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Tue, 20 Dec 2016 19:07:35 +0530 Subject: [PATCH 0050/1587] dmaengine: qcom_hidma: Wrong domain name in the email address cudeaurora.org is used in place of codeaurora.org in the contact field. Signed-off-by: Amit Kumar Signed-off-by: Vinod Koul --- .../ABI/testing/sysfs-platform-hidma | 2 +- .../ABI/testing/sysfs-platform-hidma-mgmt | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-platform-hidma b/Documentation/ABI/testing/sysfs-platform-hidma index d36441538660..fca40a54df59 100644 --- a/Documentation/ABI/testing/sysfs-platform-hidma +++ b/Documentation/ABI/testing/sysfs-platform-hidma @@ -2,7 +2,7 @@ What: /sys/devices/platform/hidma-*/chid /sys/devices/platform/QCOM8061:*/chid Date: Dec 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains the ID of the channel within the HIDMA instance. It is used to associate a given HIDMA channel with the diff --git a/Documentation/ABI/testing/sysfs-platform-hidma-mgmt b/Documentation/ABI/testing/sysfs-platform-hidma-mgmt index c2fb5d033f0e..3b6c5c9eabdc 100644 --- a/Documentation/ABI/testing/sysfs-platform-hidma-mgmt +++ b/Documentation/ABI/testing/sysfs-platform-hidma-mgmt @@ -2,7 +2,7 @@ What: /sys/devices/platform/hidma-mgmt*/chanops/chan*/priority /sys/devices/platform/QCOM8060:*/chanops/chan*/priority Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains either 0 or 1 and indicates if the DMA channel is a low priority (0) or high priority (1) channel. @@ -11,7 +11,7 @@ What: /sys/devices/platform/hidma-mgmt*/chanops/chan*/weight /sys/devices/platform/QCOM8060:*/chanops/chan*/weight Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains 0..15 and indicates the weight of the channel among equal priority channels during round robin scheduling. @@ -20,7 +20,7 @@ What: /sys/devices/platform/hidma-mgmt*/chreset_timeout_cycles /sys/devices/platform/QCOM8060:*/chreset_timeout_cycles Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains the platform specific cycle value to wait after a reset command is issued. If the value is chosen too short, @@ -32,7 +32,7 @@ What: /sys/devices/platform/hidma-mgmt*/dma_channels /sys/devices/platform/QCOM8060:*/dma_channels Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains the number of dma channels supported by one instance of HIDMA hardware. The value may change from chip to chip. @@ -41,7 +41,7 @@ What: /sys/devices/platform/hidma-mgmt*/hw_version_major /sys/devices/platform/QCOM8060:*/hw_version_major Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Version number major for the hardware. @@ -49,7 +49,7 @@ What: /sys/devices/platform/hidma-mgmt*/hw_version_minor /sys/devices/platform/QCOM8060:*/hw_version_minor Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Version number minor for the hardware. @@ -57,7 +57,7 @@ What: /sys/devices/platform/hidma-mgmt*/max_rd_xactions /sys/devices/platform/QCOM8060:*/max_rd_xactions Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains a value between 0 and 31. Maximum number of read transactions that can be issued back to back. @@ -69,7 +69,7 @@ What: /sys/devices/platform/hidma-mgmt*/max_read_request /sys/devices/platform/QCOM8060:*/max_read_request Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Size of each read request. The value needs to be a power of two and can be between 128 and 1024. @@ -78,7 +78,7 @@ What: /sys/devices/platform/hidma-mgmt*/max_wr_xactions /sys/devices/platform/QCOM8060:*/max_wr_xactions Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains a value between 0 and 31. Maximum number of write transactions that can be issued back to back. @@ -91,7 +91,7 @@ What: /sys/devices/platform/hidma-mgmt*/max_write_request /sys/devices/platform/QCOM8060:*/max_write_request Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Size of each write request. The value needs to be a power of two and can be between 128 and 1024. From adee40b265d7568296e218f079f478197ffa15bf Mon Sep 17 00:00:00 2001 From: Magnus Lilja Date: Wed, 21 Dec 2016 22:13:58 +0100 Subject: [PATCH 0051/1587] dmaengine: ipu: Make sure the interrupt routine checks all interrupts. Commit 3d8cc00073d6 ("dmaengine: ipu: Consolidate duplicated irq handlers") consolidated the two interrupts routines into one, but the remaining interrupt routine only checks the status of the error interrupts, not the normal interrupts. This patch fixes that problem (tested on i.MX31 PDK board). Fixes: 3d8cc00073d6 ("dmaengine: ipu: Consolidate duplicated irq handlers") Cc: Vinod Koul Cc: # 4.1.x Signed-off-by: Magnus Lilja Signed-off-by: Vinod Koul --- drivers/dma/ipu/ipu_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index dd184b50e5b4..284627806b88 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -272,7 +272,7 @@ static void ipu_irq_handler(struct irq_desc *desc) u32 status; int i, line; - for (i = IPU_IRQ_NR_FN_BANKS; i < IPU_IRQ_NR_BANKS; i++) { + for (i = 0; i < IPU_IRQ_NR_BANKS; i++) { struct ipu_irq_bank *bank = irq_bank + i; raw_spin_lock(&bank_lock); From 253f9f4412e0113fd83471e9a3b1aa9f85ce87c3 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 15 Dec 2016 22:03:35 +0800 Subject: [PATCH 0052/1587] dmaengine: zx: rename zx296702_dma.c to zx_dma.c ZTE ZX dma driver is not ZX296702 specific. It works for not only ZX296702 but also other ZTE ZX family platforms like ZX296718. Let's rename the file to reflect that. Signed-off-by: Shawn Guo Reviewed-by: Jun Nie Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 4 ++-- drivers/dma/Makefile | 2 +- drivers/dma/{zx296702_dma.c => zx_dma.c} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename drivers/dma/{zx296702_dma.c => zx_dma.c} (100%) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 263495d0adbd..eab7e12ee4a6 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -571,12 +571,12 @@ config XILINX_ZYNQMP_DMA Enable support for Xilinx ZynqMP DMA controller. config ZX_DMA - tristate "ZTE ZX296702 DMA support" + tristate "ZTE ZX DMA support" depends on ARCH_ZX || COMPILE_TEST select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help - Support the DMA engine for ZTE ZX296702 platform devices. + Support the DMA engine for ZTE ZX family platform devices. # driver files diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index a4fa3360e609..0b723e94d9e6 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -66,7 +66,7 @@ obj-$(CONFIG_TI_CPPI41) += cppi41.o obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o obj-$(CONFIG_TI_EDMA) += edma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o -obj-$(CONFIG_ZX_DMA) += zx296702_dma.o +obj-$(CONFIG_ZX_DMA) += zx_dma.o obj-$(CONFIG_ST_FDMA) += st_fdma.o obj-y += qcom/ diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx_dma.c similarity index 100% rename from drivers/dma/zx296702_dma.c rename to drivers/dma/zx_dma.c From fc318d64f3d91e15babac00e08354b1beb650b57 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 15 Dec 2016 22:03:36 +0800 Subject: [PATCH 0053/1587] dmaengine: zx: set DMA_CYCLIC cap_mask bit The zx_dma driver supports cyclic transfer mode. Let's set DMA_CYCLIC cap_mask bit to make that clear, and avoid unnecessary failure when clients request channel via dma_request_chan_by_mask() with DMA_CYCLIC bit set in mask. Signed-off-by: Shawn Guo Reviewed-by: Jun Nie Signed-off-by: Vinod Koul --- drivers/dma/zx_dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c index 380276d078b2..33155c6816cc 100644 --- a/drivers/dma/zx_dma.c +++ b/drivers/dma/zx_dma.c @@ -812,6 +812,7 @@ static int zx_dma_probe(struct platform_device *op) INIT_LIST_HEAD(&d->slave.channels); dma_cap_set(DMA_SLAVE, d->slave.cap_mask); dma_cap_set(DMA_MEMCPY, d->slave.cap_mask); + dma_cap_set(DMA_CYCLIC, d->slave.cap_mask); dma_cap_set(DMA_PRIVATE, d->slave.cap_mask); d->slave.dev = &op->dev; d->slave.device_free_chan_resources = zx_dma_free_chan_resources; From 156ae09245c4c49c8eb4a0898411ee260966331d Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 15 Dec 2016 22:03:37 +0800 Subject: [PATCH 0054/1587] dmaengine: zx: fix residue calculation The dma residue is defined as the free space to end of transfer buffer, which could be multiple segments chained together. So the residue calculation in zx_dma_tx_status() works for both slave_sg and cyclic case. But unfortunately, the 'index' is wrong. It should plus one, because the current segment is already occupied and shouldn't be counted into free space. This fixes the HDMI audio noise issue we see on ZX296718 with SPDIF interface. Signed-off-by: Shawn Guo Reviewed-by: Jun Nie Signed-off-by: Vinod Koul --- drivers/dma/zx_dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c index 33155c6816cc..42ff3e66c1e1 100644 --- a/drivers/dma/zx_dma.c +++ b/drivers/dma/zx_dma.c @@ -365,7 +365,8 @@ static enum dma_status zx_dma_tx_status(struct dma_chan *chan, bytes = 0; clli = zx_dma_get_curr_lli(p); - index = (clli - ds->desc_hw_lli) / sizeof(struct zx_desc_hw); + index = (clli - ds->desc_hw_lli) / + sizeof(struct zx_desc_hw) + 1; for (; index < ds->desc_num; index++) { bytes += ds->desc_hw[index].src_x; /* end of lli */ From 5bbdcbbb396196f1c94110ad7a041e90de95c4c2 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 2 Jan 2017 15:12:17 -0500 Subject: [PATCH 0055/1587] fscrypt: make test_dummy_encryption require a keyring key Currently, the test_dummy_encryption ext4 mount option, which exists only to test encrypted I/O paths with xfstests, overrides all per-inode encryption keys with a fixed key. This change minimizes test_dummy_encryption-specific code path changes by supplying a fake context for directories which are not encrypted for use when creating new directories, files, or symlinks. This allows us to properly exercise the keyring lookup, derivation, and context inheritance code paths. Before mounting a file system using test_dummy_encryption, userspace must execute the following shell commands: mode='\x00\x00\x00\x00' raw="$(printf ""\\\\x%02x"" $(seq 0 63))" if lscpu | grep "Byte Order" | grep -q Little ; then size='\x40\x00\x00\x00' else size='\x00\x00\x00\x40' fi key="${mode}${raw}${size}" keyctl new_session echo -n -e "${key}" | keyctl padd logon fscrypt:4242424242424242 @s Signed-off-by: Theodore Ts'o --- fs/crypto/keyinfo.c | 15 ++++++--------- fs/crypto/policy.c | 22 +++++++--------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 95cd4c3b06c3..80f145c8d550 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -206,12 +206,16 @@ retry: res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); if (res < 0) { - if (!fscrypt_dummy_context_enabled(inode)) + if (!fscrypt_dummy_context_enabled(inode) || + inode->i_sb->s_cop->is_encrypted(inode)) return res; + /* Fake up a context for an unencrypted directory */ + memset(&ctx, 0, sizeof(ctx)); ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; - ctx.flags = 0; + memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); + res = sizeof(ctx); } else if (res != sizeof(ctx)) { return -EINVAL; } @@ -247,12 +251,6 @@ retry: if (!raw_key) goto out; - if (fscrypt_dummy_context_enabled(inode)) { - memset(raw_key, 0x42, keysize/2); - memset(raw_key+keysize/2, 0x24, keysize - (keysize/2)); - goto got_key; - } - res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE); if (res && inode->i_sb->s_cop->key_prefix) { @@ -270,7 +268,6 @@ retry: } else if (res) { goto out; } -got_key: ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); if (!ctfm || IS_ERR(ctfm)) { res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 4c99972899c7..14b76da71269 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -198,9 +198,9 @@ EXPORT_SYMBOL(fscrypt_has_permitted_context); * @parent: Parent inode from which the context is inherited. * @child: Child inode that inherits the context from @parent. * @fs_data: private data given by FS. - * @preload: preload child i_crypt_info + * @preload: preload child i_crypt_info if true * - * Return: Zero on success, non-zero otherwise + * Return: 0 on success, -errno on failure */ int fscrypt_inherit_context(struct inode *parent, struct inode *child, void *fs_data, bool preload) @@ -221,19 +221,11 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child, return -ENOKEY; ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; - if (fscrypt_dummy_context_enabled(parent)) { - ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; - ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; - ctx.flags = 0; - memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); - res = 0; - } else { - ctx.contents_encryption_mode = ci->ci_data_mode; - ctx.filenames_encryption_mode = ci->ci_filename_mode; - ctx.flags = ci->ci_flags; - memcpy(ctx.master_key_descriptor, ci->ci_master_key, - FS_KEY_DESCRIPTOR_SIZE); - } + ctx.contents_encryption_mode = ci->ci_data_mode; + ctx.filenames_encryption_mode = ci->ci_filename_mode; + ctx.flags = ci->ci_flags; + memcpy(ctx.master_key_descriptor, ci->ci_master_key, + FS_KEY_DESCRIPTOR_SIZE); get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE); res = parent->i_sb->s_cop->set_context(child, &ctx, sizeof(ctx), fs_data); From 703ecd220d57247360f64ae0c5a08d1f2355794a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 Dec 2016 15:28:07 +0800 Subject: [PATCH 0056/1587] ACPICA: Debugger: Rename debugger OSL names ACPICA commit e76eb8b36ace880e4d475880db1128a206e57b6f This linuxized ACPICA commit is a back port result of the following linux commit: Commit: f8d31489629c125806ce4bf587c0c5c284d6d113 Subject: ACPICA: Debugger: Convert some mechanisms to OSPM specific During the back porting, it is requested by ACPICA to use expected OSL names. Suggested by Bob Moore, Fixed by Lv Zheng. Linux is not affected by this patch. Link: https://github.com/acpica/acpica/commit/e76eb8b3 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dbxface.c | 4 ++-- include/acpi/acpiosxf.h | 8 ++++---- include/acpi/platform/aclinux.h | 4 ++-- include/acpi/platform/aclinuxex.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index 124db237775d..5b8cae1796cb 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -430,7 +430,7 @@ acpi_status acpi_initialize_debugger(void) /* These were created with one unit, grab it */ - status = acpi_os_initialize_command_signals(); + status = acpi_os_initialize_debugger(); if (ACPI_FAILURE(status)) { acpi_os_printf("Could not get debugger mutex\n"); return_ACPI_STATUS(status); @@ -482,7 +482,7 @@ void acpi_terminate_debugger(void) acpi_os_sleep(100); } - acpi_os_terminate_command_signals(); + acpi_os_terminate_debugger(); } if (acpi_gbl_db_buffer) { diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index f3414c83abb1..42ab9b37f33d 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -355,12 +355,12 @@ void acpi_os_redirect_output(void *destination); acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read); #endif -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals -acpi_status acpi_os_initialize_command_signals(void); +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_debugger +acpi_status acpi_os_initialize_debugger(void); #endif -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals -void acpi_os_terminate_command_signals(void); +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_debugger +void acpi_os_terminate_debugger(void); #endif #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index e861a24f06f2..af588e0d2e99 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -156,8 +156,8 @@ */ #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_debugger +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_debugger /* * OSL interfaces used by utilities diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index 7dbb1141f546..de7648b4c729 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h @@ -129,12 +129,12 @@ static inline u8 acpi_os_readable(void *pointer, acpi_size length) return TRUE; } -static inline acpi_status acpi_os_initialize_command_signals(void) +static inline acpi_status acpi_os_initialize_debugger(void) { return AE_OK; } -static inline void acpi_os_terminate_command_signals(void) +static inline void acpi_os_terminate_debugger(void) { return; } From 123a1577b79f3eef104dc58c6ff281d5e3317d1f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 Dec 2016 15:28:14 +0800 Subject: [PATCH 0057/1587] ACPICA: Hardware: Remove bit_offset masking support ACPICA commit bc7c5291865e099ce01f345d0265f0eba6997e23 This linuxized ACPICA commit is a back port result of the following Linux commit: Commit c3bc26d4b4e36f0dc458eea8b1f722d8a8d9addd Subject: ACPICA: ACPI 2.0, Hardware: Add access_width/bit_offset support in acpi_hw_read() The commit was in ACPICA and Linux upstream, after reversion and re-integration, it is designed not to do bit_offset masking (bit_offset is only used to determine the boundary of the register) inside of the ACPICA APIs, but let the callers to do that as: 1. Register can have different masking schemes (W1C, W0C); 2. Normally a mask value will be provided for region format GAS. So actually the callers are the only ones having the knowledge of masking the register values. Suggested by Bob Moore, Fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/bc7c5291 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwregs.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 3b7fb99362b6..115c2235decb 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -252,20 +252,6 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) &value32, access_width); } - - /* - * Use offset style bit masks because: - * bit_offset < access_width/bit_width < access_width, and - * access_width is ensured to be less than 32-bits by - * acpi_hw_validate_register(). - */ - if (bit_offset) { - value32 &= ACPI_MASK_BITS_BELOW(bit_offset); - bit_offset = 0; - } - if (bit_width < access_width) { - value32 &= ACPI_MASK_BITS_ABOVE(bit_width); - } } /* From dc4c7376657573a73e75df2d7b094ae40a859f98 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 Dec 2016 15:28:23 +0800 Subject: [PATCH 0058/1587] ACPICA: Hardware: Add access_width/bit_offset support in acpi_hw_write() ACPICA commit 1ecab20bbe69a176dfb6da7210fe77aa6b3ad680 This patch adds access_width/bit_offset support in acpi_hw_write(). Link: https://github.com/acpica/acpica/commit/1ecab20b Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwregs.c | 60 +++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 115c2235decb..2bc3425d3b6a 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -292,6 +292,12 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) { u64 address; + u8 access_width; + u32 bit_width; + u8 bit_offset; + u64 value64; + u32 value32; + u8 index; acpi_status status; ACPI_FUNCTION_NAME(hw_write); @@ -303,23 +309,61 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) return (status); } + /* Convert access_width into number of bits based */ + + access_width = acpi_hw_get_access_bit_width(reg, 32); + bit_width = reg->bit_offset + reg->bit_width; + bit_offset = reg->bit_offset; + /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ - if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { - status = acpi_os_write_memory((acpi_physical_address) - address, (u64)value, - reg->bit_width); - } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + index = 0; + while (bit_width) { + /* + * Use offset style bit reads because "Index * AccessWidth" is + * ensured to be less than 32-bits by acpi_hw_validate_register(). + */ + value32 = ACPI_GET_BITS(&value, index * access_width, + ACPI_MASK_BITS_ABOVE_32(access_width)); - status = acpi_hw_write_port((acpi_io_address) - address, value, reg->bit_width); + if (bit_offset >= access_width) { + bit_offset -= access_width; + } else { + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + value64 = (u64)value32; + status = + acpi_os_write_memory((acpi_physical_address) + address + + index * + ACPI_DIV_8 + (access_width), + value64, access_width); + } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + + status = acpi_hw_write_port((acpi_io_address) + address + + index * + ACPI_DIV_8 + (access_width), + value32, + access_width); + } + } + + /* + * Index * access_width is ensured to be less than 32-bits by + * acpi_hw_validate_register(). + */ + bit_width -= + bit_width > access_width ? access_width : bit_width; + index++; } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, reg->bit_width, ACPI_FORMAT_UINT64(address), + value, access_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); From cc573b97c89e5262d5404bc515a4c1e7eb364fff Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 Dec 2016 15:28:29 +0800 Subject: [PATCH 0059/1587] ACPICA: Utilities: Add power of two rounding support ACPICA commit cbb0294649cbd7e8bd6107e4329461a6a7a0d967 This patch adds power of two rounding support up to 32 bits. The result of the shift operations rearching to the boundary of the cpu word is unpredicatable, so 64-bit roundings are not supported in order to make sure no rounded shift-overs. This support may not be performance friendly, so the APIs might be overridden by the hosts implementations with ACPI_USE_NATIVE_BIT_FINDER defined. Link: https://github.com/acpica/acpica/commit/cbb02946 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acmacros.h | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index a3b95431b7c5..6537cbd17bd8 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -262,6 +262,66 @@ /* Generic (power-of-two) rounding */ +#ifndef ACPI_USE_NATIVE_BIT_FINDER + +#define __ACPI_FIND_LAST_BIT_2(a, r) ((((u8) (a)) & 0x02) ? (r)+1 : (r)) +#define __ACPI_FIND_LAST_BIT_4(a, r) ((((u8) (a)) & 0x0C) ? \ + __ACPI_FIND_LAST_BIT_2 ((a)>>2, (r)+2) : \ + __ACPI_FIND_LAST_BIT_2 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_8(a, r) ((((u8) (a)) & 0xF0) ? \ + __ACPI_FIND_LAST_BIT_4 ((a)>>4, (r)+4) : \ + __ACPI_FIND_LAST_BIT_4 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_16(a, r) ((((u16) (a)) & 0xFF00) ? \ + __ACPI_FIND_LAST_BIT_8 ((a)>>8, (r)+8) : \ + __ACPI_FIND_LAST_BIT_8 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_32(a, r) ((((u32) (a)) & 0xFFFF0000) ? \ + __ACPI_FIND_LAST_BIT_16 ((a)>>16, (r)+16) : \ + __ACPI_FIND_LAST_BIT_16 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_64(a, r) ((((u64) (a)) & 0xFFFFFFFF00000000) ? \ + __ACPI_FIND_LAST_BIT_32 ((a)>>32, (r)+32) : \ + __ACPI_FIND_LAST_BIT_32 ((a), (r))) + +#define ACPI_FIND_LAST_BIT_8(a) ((a) ? __ACPI_FIND_LAST_BIT_8 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_16(a) ((a) ? __ACPI_FIND_LAST_BIT_16 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_32(a) ((a) ? __ACPI_FIND_LAST_BIT_32 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_64(a) ((a) ? __ACPI_FIND_LAST_BIT_64 (a, 1) : 0) + +#define __ACPI_FIND_FIRST_BIT_2(a, r) ((((u8) (a)) & 0x01) ? (r) : (r)+1) +#define __ACPI_FIND_FIRST_BIT_4(a, r) ((((u8) (a)) & 0x03) ? \ + __ACPI_FIND_FIRST_BIT_2 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_2 ((a)>>2, (r)+2)) +#define __ACPI_FIND_FIRST_BIT_8(a, r) ((((u8) (a)) & 0x0F) ? \ + __ACPI_FIND_FIRST_BIT_4 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_4 ((a)>>4, (r)+4)) +#define __ACPI_FIND_FIRST_BIT_16(a, r) ((((u16) (a)) & 0x00FF) ? \ + __ACPI_FIND_FIRST_BIT_8 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_8 ((a)>>8, (r)+8)) +#define __ACPI_FIND_FIRST_BIT_32(a, r) ((((u32) (a)) & 0x0000FFFF) ? \ + __ACPI_FIND_FIRST_BIT_16 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_16 ((a)>>16, (r)+16)) +#define __ACPI_FIND_FIRST_BIT_64(a, r) ((((u64) (a)) & 0x00000000FFFFFFFF) ? \ + __ACPI_FIND_FIRST_BIT_32 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_32 ((a)>>32, (r)+32)) + +#define ACPI_FIND_FIRST_BIT_8(a) ((a) ? __ACPI_FIND_FIRST_BIT_8 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_16(a) ((a) ? __ACPI_FIND_FIRST_BIT_16 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_32(a) ((a) ? __ACPI_FIND_FIRST_BIT_32 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_64(a) ((a) ? __ACPI_FIND_FIRST_BIT_64 (a, 1) : 0) + +#endif /* ACPI_USE_NATIVE_BIT_FINDER */ + +#define ACPI_ROUND_UP_POWER_OF_TWO_8(a) ((u8) \ + (((u16) 1) << ACPI_FIND_LAST_BIT_8 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_8(a) ((u8) \ + (((u16) 1) << (ACPI_FIND_LAST_BIT_8 ((a)) - 1))) +#define ACPI_ROUND_UP_POWER_OF_TWO_16(a) ((u16) \ + (((u32) 1) << ACPI_FIND_LAST_BIT_16 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_16(a) ((u16) \ + (((u32) 1) << (ACPI_FIND_LAST_BIT_16 ((a)) - 1))) +#define ACPI_ROUND_UP_POWER_OF_TWO_32(a) ((u32) \ + (((u64) 1) << ACPI_FIND_LAST_BIT_32 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_32(a) ((u32) \ + (((u64) 1) << (ACPI_FIND_LAST_BIT_32 ((a)) - 1))) #define ACPI_IS_ALIGNED(a, s) (((a) & ((s) - 1)) == 0) #define ACPI_IS_POWER_OF_TWO(a) ACPI_IS_ALIGNED(a, a) From 04cf05379972644209a94dc524d619e4936ad9c8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 Dec 2016 15:28:36 +0800 Subject: [PATCH 0060/1587] ACPICA: Hardware: Sort access bit width algorithm ACPICA commit 365b321a31cb701957c055cae2d2161577147252 GAS can be in register or register region format, so we need to improve our "register" format detection code in order not to regress. Such detection may be still experimental, and is generated according to the current known facts. Link: https://github.com/acpica/acpica/commit/365b321a Link: https://bugzilla.kernel.org/show_bug.cgi?id=151501 Reported-and-tested-by: Andrey Skvortsov Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwregs.c | 79 ++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 2bc3425d3b6a..50b90707d755 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -52,7 +52,8 @@ ACPI_MODULE_NAME("hwregs") #if (!ACPI_REDUCED_HARDWARE) /* Local Prototypes */ static u8 -acpi_hw_get_access_bit_width(struct acpi_generic_address *reg, +acpi_hw_get_access_bit_width(u64 address, + struct acpi_generic_address *reg, u8 max_bit_width); static acpi_status @@ -71,7 +72,8 @@ acpi_hw_write_multiple(u32 value, * * FUNCTION: acpi_hw_get_access_bit_width * - * PARAMETERS: reg - GAS register structure + * PARAMETERS: address - GAS register address + * reg - GAS register structure * max_bit_width - Max bit_width supported (32 or 64) * * RETURN: Status @@ -81,27 +83,59 @@ acpi_hw_write_multiple(u32 value, ******************************************************************************/ static u8 -acpi_hw_get_access_bit_width(struct acpi_generic_address *reg, u8 max_bit_width) +acpi_hw_get_access_bit_width(u64 address, + struct acpi_generic_address *reg, u8 max_bit_width) { - if (!reg->access_width) { - if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { - max_bit_width = 32; - } + u8 access_bit_width; - /* - * Detect old register descriptors where only the bit_width field - * makes senses. - */ - if (reg->bit_width < max_bit_width && - !reg->bit_offset && reg->bit_width && - ACPI_IS_POWER_OF_TWO(reg->bit_width) && - ACPI_IS_ALIGNED(reg->bit_width, 8)) { - return (reg->bit_width); - } - return (max_bit_width); + /* + * GAS format "register", used by FADT: + * 1. Detected if bit_offset is 0 and bit_width is 8/16/32/64; + * 2. access_size field is ignored and bit_width field is used for + * determining the boundary of the IO accesses. + * GAS format "region", used by APEI registers: + * 1. Detected if bit_offset is not 0 or bit_width is not 8/16/32/64; + * 2. access_size field is used for determining the boundary of the + * IO accesses; + * 3. bit_offset/bit_width fields are used to describe the "region". + * + * Note: This algorithm assumes that the "Address" fields should always + * contain aligned values. + */ + if (!reg->bit_offset && reg->bit_width && + ACPI_IS_POWER_OF_TWO(reg->bit_width) && + ACPI_IS_ALIGNED(reg->bit_width, 8)) { + access_bit_width = reg->bit_width; + } else if (reg->access_width) { + access_bit_width = (1 << (reg->access_width + 2)); } else { - return (1 << (reg->access_width + 2)); + access_bit_width = + ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset + + reg->bit_width); + if (access_bit_width <= 8) { + access_bit_width = 8; + } else { + while (!ACPI_IS_ALIGNED(address, access_bit_width >> 3)) { + access_bit_width >>= 1; + } + } } + + /* Maximum IO port access bit width is 32 */ + + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + max_bit_width = 32; + } + + /* + * Return access width according to the requested maximum access bit width, + * as the caller should know the format of the register and may enforce + * a 32-bit accesses. + */ + if (access_bit_width < max_bit_width) { + return (access_bit_width); + } + return (max_bit_width); } /****************************************************************************** @@ -163,7 +197,8 @@ acpi_hw_validate_register(struct acpi_generic_address *reg, /* Validate the bit_width, convert access_width into number of bits */ - access_width = acpi_hw_get_access_bit_width(reg, max_bit_width); + access_width = + acpi_hw_get_access_bit_width(*address, reg, max_bit_width); bit_width = ACPI_ROUND_UP(reg->bit_offset + reg->bit_width, access_width); if (max_bit_width < bit_width) { @@ -219,7 +254,7 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) * into number of bits based */ *value = 0; - access_width = acpi_hw_get_access_bit_width(reg, 32); + access_width = acpi_hw_get_access_bit_width(address, reg, 32); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; @@ -311,7 +346,7 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) /* Convert access_width into number of bits based */ - access_width = acpi_hw_get_access_bit_width(reg, 32); + access_width = acpi_hw_get_access_bit_width(address, reg, 32); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; From fcfb45531d7ef71a19caaa0a983611ca57ec04fe Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 28 Dec 2016 15:28:43 +0800 Subject: [PATCH 0061/1587] ACPICA: Macro header: Fix some typos in comments ACPICA commit efc97d1d209947d6990ec81a192c6b2589d3e368 No functional change. Link: https://github.com/acpica/acpica/commit/efc97d1 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acmacros.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 6537cbd17bd8..31b61a0a7474 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -46,7 +46,7 @@ /* * Extract data using a pointer. Any more than a byte and we - * get into potential aligment issues -- see the STORE macros below. + * get into potential alignment issues -- see the STORE macros below. * Use with care. */ #define ACPI_CAST8(ptr) ACPI_CAST_PTR (u8, (ptr)) @@ -63,7 +63,7 @@ #define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (u64) (val)) /* - * printf() format helper. This macros is a workaround for the difficulties + * printf() format helper. This macro is a workaround for the difficulties * with emitting 64-bit integers and 64-bit pointers with the same code * for both 32-bit and 64-bit hosts. */ @@ -260,7 +260,7 @@ #define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1)) -/* Generic (power-of-two) rounding */ +/* Generic bit manipulation */ #ifndef ACPI_USE_NATIVE_BIT_FINDER @@ -310,6 +310,8 @@ #endif /* ACPI_USE_NATIVE_BIT_FINDER */ +/* Generic (power-of-two) rounding */ + #define ACPI_ROUND_UP_POWER_OF_TWO_8(a) ((u8) \ (((u16) 1) << ACPI_FIND_LAST_BIT_8 ((a) - 1))) #define ACPI_ROUND_DOWN_POWER_OF_TWO_8(a) ((u8) \ @@ -330,8 +332,8 @@ * Bit positions start at zero. * MASK_BITS_ABOVE creates a mask starting AT the position and above * MASK_BITS_BELOW creates a mask starting one bit BELOW the position - * MASK_BITS_ABOVE/BELOW accpets a bit offset to create a mask - * MASK_BITS_ABOVE/BELOW_32/64 accpets a bit width to create a mask + * MASK_BITS_ABOVE/BELOW accepts a bit offset to create a mask + * MASK_BITS_ABOVE/BELOW_32/64 accepts a bit width to create a mask * Note: The ACPI_INTEGER_BIT_SIZE check is used to bypass compiler * differences with the shift operator */ @@ -449,7 +451,7 @@ */ #ifndef ACPI_NO_ERROR_MESSAGES /* - * Error reporting. Callers module and line number are inserted by AE_INFO, + * Error reporting. The callers module and line number are inserted by AE_INFO, * the plist contains a set of parens to allow variable-length lists. * These macros are used for both the debug and non-debug versions of the code. */ From 0fc5e8f4e4b33ddfa1d1d673fcd420d6e13eb076 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 Dec 2016 15:28:49 +0800 Subject: [PATCH 0062/1587] ACPICA: Hardware: Add sleep register hooks ACPICA commit ba665dc8e20d9f7730466a659564dd6c557a6cbc In Linux, para-virtualization implmentation hooks critical register writes to prevent real hardware operations. This increases divergences when the sleep registers are cracked in Linux resident ACPICA. This patch tries to introduce a single OSL to reduce the divergences. Link: https://github.com/acpica/acpica/commit/ba665dc8 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwesleep.c | 35 +++++++++---------- drivers/acpi/acpica/hwsleep.c | 11 +++--- drivers/acpi/osl.c | 27 ++++++++++++-- include/acpi/acexcep.h | 9 ++--- include/acpi/acpiosxf.h | 4 +++ .../os_specific/service_layers/osunixxf.c | 22 ++++++++++++ 6 files changed, 76 insertions(+), 32 deletions(-) diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 3f2fb4b31fdc..9023a1b87a54 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -43,7 +43,6 @@ */ #include -#include #include "accommon.h" #define _COMPONENT ACPI_HARDWARE @@ -103,7 +102,7 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument) acpi_status acpi_hw_extended_sleep(u8 sleep_state) { acpi_status status; - u8 sleep_type_value; + u8 sleep_control; u64 sleep_status; ACPI_FUNCTION_TRACE(hw_extended_sleep); @@ -125,18 +124,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) acpi_gbl_system_awake_and_running = FALSE; - /* Flush caches, as per ACPI specification */ - - ACPI_FLUSH_CPU_CACHE(); - - status = acpi_os_prepare_extended_sleep(sleep_state, - acpi_gbl_sleep_type_a, - acpi_gbl_sleep_type_b); - if (ACPI_SKIP(status)) - return_ACPI_STATUS(AE_OK); - if (ACPI_FAILURE(status)) - return_ACPI_STATUS(status); - /* * Set the SLP_TYP and SLP_EN bits. * @@ -146,12 +133,22 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Entering sleep state [S%u]\n", sleep_state)); - sleep_type_value = - ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & - ACPI_X_SLEEP_TYPE_MASK); + sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & + ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE; - status = acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE), - &acpi_gbl_FADT.sleep_control); + /* Flush caches, as per ACPI specification */ + + ACPI_FLUSH_CPU_CACHE(); + + status = acpi_os_enter_sleep(sleep_state, sleep_control, 0); + if (status == AE_CTRL_TERMINATE) { + return_ACPI_STATUS(AE_OK); + } + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_write((u64)sleep_control, &acpi_gbl_FADT.sleep_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index d00c9810845b..563c5d91663f 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -43,7 +43,6 @@ */ #include -#include #include "accommon.h" #define _COMPONENT ACPI_HARDWARE @@ -152,12 +151,14 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) ACPI_FLUSH_CPU_CACHE(); - status = acpi_os_prepare_sleep(sleep_state, pm1a_control, - pm1b_control); - if (ACPI_SKIP(status)) + status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control); + if (status == AE_CTRL_TERMINATE) { return_ACPI_STATUS(AE_OK); - if (ACPI_FAILURE(status)) + } + if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); + } + /* Write #2: Write both SLP_TYP + SLP_EN */ status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 57fb5f468ac2..db78d353bab1 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1686,7 +1686,7 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control, if (rc < 0) return AE_ERROR; else if (rc > 0) - return AE_CTRL_SKIP; + return AE_CTRL_TERMINATE; return AE_OK; } @@ -1697,6 +1697,7 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, __acpi_os_prepare_sleep = func; } +#if (ACPI_REDUCED_HARDWARE) acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, u32 val_b) { @@ -1707,13 +1708,35 @@ acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, if (rc < 0) return AE_ERROR; else if (rc > 0) - return AE_CTRL_SKIP; + return AE_CTRL_TERMINATE; return AE_OK; } +#else +acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, + u32 val_b) +{ + return AE_OK; +} +#endif void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, u32 val_a, u32 val_b)) { __acpi_os_prepare_extended_sleep = func; } + +acpi_status acpi_os_enter_sleep(u8 sleep_state, + u32 reg_a_value, u32 reg_b_value) +{ + acpi_status status; + + if (acpi_gbl_reduced_hardware) + status = acpi_os_prepare_extended_sleep(sleep_state, + reg_a_value, + reg_b_value); + else + status = acpi_os_prepare_sleep(sleep_state, + reg_a_value, reg_b_value); + return status; +} diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 2c396344a7a2..1155002761a7 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -91,7 +91,6 @@ struct acpi_exception_info { #define ACPI_SUCCESS(a) (!(a)) #define ACPI_FAILURE(a) (a) -#define ACPI_SKIP(a) (a == AE_CTRL_SKIP) #define AE_OK (acpi_status) 0x0000 /* @@ -211,11 +210,10 @@ struct acpi_exception_info { #define AE_CTRL_TRANSFER EXCEP_CTL (0x0008) #define AE_CTRL_BREAK EXCEP_CTL (0x0009) #define AE_CTRL_CONTINUE EXCEP_CTL (0x000A) -#define AE_CTRL_SKIP EXCEP_CTL (0x000B) -#define AE_CTRL_PARSE_CONTINUE EXCEP_CTL (0x000C) -#define AE_CTRL_PARSE_PENDING EXCEP_CTL (0x000D) +#define AE_CTRL_PARSE_CONTINUE EXCEP_CTL (0x000B) +#define AE_CTRL_PARSE_PENDING EXCEP_CTL (0x000C) -#define AE_CODE_CTRL_MAX 0x000D +#define AE_CODE_CTRL_MAX 0x000C /* Exception strings for acpi_format_exception */ @@ -378,7 +376,6 @@ static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = { EXCEP_TXT("AE_CTRL_TRANSFER", "Transfer control to called method"), EXCEP_TXT("AE_CTRL_BREAK", "A Break has been executed"), EXCEP_TXT("AE_CTRL_CONTINUE", "A Continue has been executed"), - EXCEP_TXT("AE_CTRL_SKIP", "Not currently used"), EXCEP_TXT("AE_CTRL_PARSE_CONTINUE", "Used to skip over bad opcodes"), EXCEP_TXT("AE_CTRL_PARSE_PENDING", "Used to implement AML While loops") }; diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 42ab9b37f33d..e166013b4712 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -333,6 +333,10 @@ u64 acpi_os_get_timer(void); acpi_status acpi_os_signal(u32 function, void *info); #endif +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_enter_sleep +acpi_status acpi_os_enter_sleep(u8 sleep_state, u32 rega_value, u32 regb_value); +#endif + /* * Debug print routines */ diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c index 10648aaf6164..e41c2644c347 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixxf.c +++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c @@ -316,6 +316,28 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table, return (AE_SUPPORT); } +/****************************************************************************** + * + * FUNCTION: acpi_os_enter_sleep + * + * PARAMETERS: sleep_state - Which sleep state to enter + * rega_value - Register A value + * regb_value - Register B value + * + * RETURN: Status + * + * DESCRIPTION: A hook before writing sleep registers to enter the sleep + * state. Return AE_CTRL_TERMINATE to skip further sleep register + * writes. + * + *****************************************************************************/ + +acpi_status acpi_os_enter_sleep(u8 sleep_state, u32 rega_value, u32 regb_value) +{ + + return (AE_OK); +} + /****************************************************************************** * * FUNCTION: acpi_os_redirect_output From 23741569dc31052c786621db276779e0ed431e62 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Dec 2016 15:28:56 +0800 Subject: [PATCH 0063/1587] ACPICA: Linux-specific header: Add support for s390x compilation ACPICA commit ecac9504e32d3b501c8cb021afb253b4a83fc82f Adds s390x as a 64-bit architecture. Link: https://github.com/acpica/acpica/commit/ecac9504 Signed-off-by: Colin Ian King Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/aclinux.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index af588e0d2e99..252359e462c9 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -201,7 +201,8 @@ #define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread)) #if defined(__ia64__) || defined(__x86_64__) ||\ - defined(__aarch64__) || defined(__PPC64__) + defined(__aarch64__) || defined(__PPC64__) ||\ + defined(__s390x__) #define ACPI_MACHINE_WIDTH 64 #define COMPILER_DEPENDENT_INT64 long #define COMPILER_DEPENDENT_UINT64 unsigned long From 0822d4f4f8db98c4619e6136fc375d4324eff788 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 Dec 2016 15:29:03 +0800 Subject: [PATCH 0064/1587] ACPICA: MSVC: Fix MSVC6 build issues ACPICA commit fa0680030a2969e1085563da633713e1c321637c Build environment has changed because of new improvements: 1. New files are split 2. New inclusion order This patch updates MSVC project files accordingly. Linux is not affected by this patch. Link: https://github.com/acpica/acpica/commit/fa068003 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/acenv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 34cce729109c..cf93b662a385 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -357,7 +357,7 @@ #include #include #include -#ifdef ACPI_APPLICATION +#if defined (ACPI_APPLICATION) || defined(ACPI_LIBRARY) #include #include #include From 55333089390909f3aee73764836bc85ba18e6b4e Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 Dec 2016 15:29:10 +0800 Subject: [PATCH 0065/1587] ACPICA: EFI: Add efihello demo application ACPICA commit 3fcc59f4755607dd066ac8ef869f0aa95e871b84 This patch adds a demo EFI application for stdin/stdout testing. This utility can be used to narrow down root causes of porting issues. Linux is not affected by this patch. Link: https://github.com/acpica/acpica/commit/3fcc59f4 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/acenv.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index cf93b662a385..926efe997479 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -75,7 +75,8 @@ (defined ACPI_NAMES_APP) || \ (defined ACPI_SRC_APP) || \ (defined ACPI_XTRACT_APP) || \ - (defined ACPI_EXAMPLE_APP) + (defined ACPI_EXAMPLE_APP) || \ + (defined ACPI_EFI_HELLO) #define ACPI_APPLICATION #define ACPI_SINGLE_THREADED #define USE_NATIVE_ALLOCATE_ZEROED From a654b8ca6d28736995de767ba62e801fd806a3b2 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Wed, 28 Dec 2016 15:29:17 +0800 Subject: [PATCH 0066/1587] ACPICA: Disassembler: Add Switch/Case disassembly support ACPICA commit 0f6cc80e8af519a3c31184367b0a9be7a399cf53 iasl compiles Switch/Case statements into a single iteration While loop with If/Else statements. This patch adds support to recognize this generated compiler output and disassemble it back to the original Switch statement. Linux kernel is not affected by this patch. Link: https://github.com/acpica/acpica/commit/0f6cc80e Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 792660054992..7b97801d907d 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -770,7 +770,7 @@ union acpi_parse_value { char *operator_symbol;/* Used for C-style operator name strings */\ char aml_op_name[16]) /* Op name (debug only) */ -/* Flags for disasm_flags field above */ +/* Internal opcodes for disasm_opcode field above */ #define ACPI_DASM_BUFFER 0x00 /* Buffer is a simple data buffer */ #define ACPI_DASM_RESOURCE 0x01 /* Buffer is a Resource Descriptor */ @@ -783,7 +783,10 @@ union acpi_parse_value { #define ACPI_DASM_LNOT_PREFIX 0x08 /* Start of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_LNOT_SUFFIX 0x09 /* End of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_HID_STRING 0x0A /* String is a _HID or _CID */ -#define ACPI_DASM_IGNORE 0x0B /* Not used at this time */ +#define ACPI_DASM_IGNORE_SINGLE 0x0B /* Ignore the opcode but not it's children */ +#define ACPI_DASM_SWITCH_PREDICATE 0x0C /* Object is a predicate for a Switch or Case block */ +#define ACPI_DASM_CASE 0x0D /* If/Else is a Case in a Switch/Case block */ +#define ACPI_DASM_DEFAULT 0x0E /* Else is a Default in a Switch/Case block */ /* * Generic operation (for example: If, While, Store) From 7225d0467c59e55566df396d6ecd5baf26ef3d9b Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 28 Dec 2016 15:29:22 +0800 Subject: [PATCH 0067/1587] ACPICA: Utilities: Update debug output ACPICA commit 082b5b3ee31f74735e166858eeda025288604a5a Enhancement of miscellaneous debug output. Link: https://github.com/acpica/acpica/commit/082b5b3e Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utdecode.c | 4 ++-- drivers/acpi/acpica/utdelete.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index b3d8421cfb80..c6f2ce17af82 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -238,7 +238,7 @@ const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) if (!obj_desc) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n")); - return_PTR("[NULL Object Descriptor]"); + return_STR("[NULL Object Descriptor]"); } /* These descriptor types share a common area */ @@ -251,7 +251,7 @@ const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) acpi_ut_get_descriptor_name(obj_desc), obj_desc)); - return_PTR("Invalid object"); + return_STR("Invalid object"); } return_STR(acpi_ut_get_type_name(obj_desc->common.type)); diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 529d6c38ea7c..5cdd707040e2 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -421,8 +421,10 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) } ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, - "Obj %p Type %.2X Refs %.2X [Incremented]\n", - object, object->common.type, new_count)); + "Obj %p Type %.2X [%s] Refs %.2X [Incremented]\n", + object, object->common.type, + acpi_ut_get_object_type_name(object), + new_count)); break; case REF_DECREMENT: From 57707a9a7780fab426b8ae9b4c7b65b912a748b3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 28 Dec 2016 15:29:28 +0800 Subject: [PATCH 0068/1587] ACPICA: Resources: Not a valid resource if buffer length too long ACPICA commit 9f76de2d249b18804e35fb55d14b1c2604d627a1 ACPICA commit b2e89d72ef1e9deefd63c3fd1dee90f893575b3a ACPICA commit 23b5bbe6d78afd3c5abf3adb91a1b098a3000b2e The declared buffer length must be the same as the length of the byte initializer list, otherwise not a valid resource descriptor. Link: https://github.com/acpica/acpica/commit/9f76de2d Link: https://github.com/acpica/acpica/commit/b2e89d72 Link: https://github.com/acpica/acpica/commit/23b5bbe6 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utresrc.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index 1de3376da66a..2ad99ea3d496 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -421,8 +421,10 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE(ut_walk_aml_resources); - /* The absolute minimum resource template is one end_tag descriptor */ - + /* + * The absolute minimum resource template is one end_tag descriptor. + * However, we will treat a lone end_tag as just a simple buffer. + */ if (aml_length < sizeof(struct aml_resource_end_tag)) { return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } @@ -454,9 +456,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, /* Invoke the user function */ if (user_function) { - status = - user_function(aml, length, offset, resource_index, - context); + status = user_function(aml, length, offset, + resource_index, context); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -480,6 +481,12 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, *context = aml; } + /* Check if buffer is defined to be longer than the resource length */ + + if (aml_length > (offset + length)) { + return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); + } + /* Normal exit */ return_ACPI_STATUS(AE_OK); From ddf9bd4089b549ff7be3f4d0dbf19d4b9267d679 Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Tue, 13 Dec 2016 14:40:44 +0100 Subject: [PATCH 0069/1587] dmaengine: stm32-dma: Fix typo in Kconfig As STM32 DMA driver is only used as buit-in driver, it couldn't be used as module. Signed-off-by: M'boumba Cedric Madianga Reviewed-by: Ludovic BARRE Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 263495d0adbd..96da57aeaa4d 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -458,7 +458,7 @@ config STM32_DMA help Enable support for the on-chip DMA controller on STMicroelectronics STM32 MCUs. - If you have a board based on such a MCU and wish to use DMA say Y or M + If you have a board based on such a MCU and wish to use DMA say Y here. config S3C24XX_DMAC From 16545502d70641af0fc4d2cc0b2789cf27d9ca9d Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Tue, 13 Dec 2016 14:40:45 +0100 Subject: [PATCH 0070/1587] dt-bindings: stm32-dma: Fix typo regarding DMA client binding Only four cells are required for dma client binding not five. Signed-off-by: M'boumba Cedric Madianga Reviewed-by: Ludovic BARRE Acked-by: Rob Herring Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/stm32-dma.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/stm32-dma.txt b/Documentation/devicetree/bindings/dma/stm32-dma.txt index 70cd13f1588a..4408af693d0c 100644 --- a/Documentation/devicetree/bindings/dma/stm32-dma.txt +++ b/Documentation/devicetree/bindings/dma/stm32-dma.txt @@ -40,8 +40,7 @@ Example: DMA clients connected to the STM32 DMA controller must use the format described in the dma.txt file, using a five-cell specifier for each -channel: a phandle plus four integer cells. -The four cells in order are: +channel: a phandle to the DMA controller plus the following four integer cells: 1. The channel id 2. The request line number @@ -61,7 +60,7 @@ The four cells in order are: 0x1: medium 0x2: high 0x3: very high -5. A 32bit mask specifying the DMA FIFO threshold configuration which are device +4. A 32bit mask specifying the DMA FIFO threshold configuration which are device dependent: -bit 0-1: Fifo threshold 0x0: 1/4 full FIFO From 8d1b76f031ce60c50d03674e6d1db0c5e5f55945 Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Tue, 13 Dec 2016 14:40:47 +0100 Subject: [PATCH 0071/1587] dmaengine: stm32-dma: Rework starting transfer management This patch reworks the way to manage transfer starting. Now, starting DMA is only allowed when the channel is not busy. Then, stm32_dma_start_transfer is declared as void. At least, after each transfer completion, we start the next transfer if a new descriptor as been queued in the issued list during an ongoing transfer. Signed-off-by: M'boumba Cedric Madianga Reviewed-by: Ludovic BARRE Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 3688d0873a3e..a8c2ad686173 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -421,7 +421,7 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); } -static int stm32_dma_start_transfer(struct stm32_dma_chan *chan) +static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) { struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); struct virt_dma_desc *vdesc; @@ -432,12 +432,12 @@ static int stm32_dma_start_transfer(struct stm32_dma_chan *chan) ret = stm32_dma_disable_chan(chan); if (ret < 0) - return ret; + return; if (!chan->desc) { vdesc = vchan_next_desc(&chan->vchan); if (!vdesc) - return -EPERM; + return; chan->desc = to_stm32_dma_desc(vdesc); chan->next_sg = 0; @@ -471,7 +471,7 @@ static int stm32_dma_start_transfer(struct stm32_dma_chan *chan) chan->busy = true; - return 0; + dev_dbg(chan2dev(chan), "vchan %p: started\n", &chan->vchan); } static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) @@ -552,15 +552,13 @@ static void stm32_dma_issue_pending(struct dma_chan *c) { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); unsigned long flags; - int ret; spin_lock_irqsave(&chan->vchan.lock, flags); - if (!chan->busy) { - if (vchan_issue_pending(&chan->vchan) && !chan->desc) { - ret = stm32_dma_start_transfer(chan); - if ((!ret) && (chan->desc->cyclic)) - stm32_dma_configure_next_sg(chan); - } + if (vchan_issue_pending(&chan->vchan) && !chan->desc && !chan->busy) { + dev_dbg(chan2dev(chan), "vchan %p: issued\n", &chan->vchan); + stm32_dma_start_transfer(chan); + if (chan->desc->cyclic) + stm32_dma_configure_next_sg(chan); } spin_unlock_irqrestore(&chan->vchan.lock, flags); } From 2b12c5580e0a4c0ffd513d1522dd39b2464fb207 Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Tue, 13 Dec 2016 14:40:48 +0100 Subject: [PATCH 0072/1587] dmaengine: stm32-dma: Fix residue computation issue in cyclic mode This patch resolves the residue computation issue detected in cyclic mode. Now, in cyclic mode, we increment next_sg variable as soon as a period is transferred instead of after pushing a new sg request. Then, we take into account that after transferring a complete buffer, the next_sg variable is equal to 0. Signed-off-by: M'boumba Cedric Madianga Reviewed-by: Ludovic BARRE Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index a8c2ad686173..8a29b028d39e 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -500,8 +500,6 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n", stm32_dma_read(dmadev, STM32_DMA_SM1AR(id))); } - - chan->next_sg++; } } @@ -510,6 +508,7 @@ static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan) if (chan->desc) { if (chan->desc->cyclic) { vchan_cyclic_callback(&chan->desc->vdesc); + chan->next_sg++; stm32_dma_configure_next_sg(chan); } else { chan->busy = false; @@ -846,26 +845,40 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } +static u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan) +{ + u32 dma_scr, width, ndtr; + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); + + dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); + width = STM32_DMA_SCR_PSIZE_GET(dma_scr); + ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); + + return ndtr << width; +} + static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, struct stm32_dma_desc *desc, u32 next_sg) { - struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); - u32 dma_scr, width, residue, count; + u32 residue = 0; int i; - residue = 0; + /* + * In cyclic mode, for the last period, residue = remaining bytes from + * NDTR + */ + if (chan->desc->cyclic && next_sg == 0) + return stm32_dma_get_remaining_bytes(chan); + /* + * For all other periods in cyclic mode, and in sg mode, + * residue = remaining bytes from NDTR + remaining periods/sg to be + * transferred + */ for (i = next_sg; i < desc->num_sgs; i++) residue += desc->sg_req[i].len; - - if (next_sg != 0) { - dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); - width = STM32_DMA_SCR_PSIZE_GET(dma_scr); - count = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); - - residue += count << width; - } + residue += stm32_dma_get_remaining_bytes(chan); return residue; } From dc808675104b920f2be1ac4bf1e9aa57680f0699 Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Tue, 13 Dec 2016 14:40:50 +0100 Subject: [PATCH 0073/1587] dmaengine: stm32-dma: Add synchronization support Implement the new device_synchronize() callback to allow proper synchronization when stopping a channel. Signed-off-by: M'boumba Cedric Madianga Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 8a29b028d39e..53b2ee79cc0e 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -403,6 +403,13 @@ static int stm32_dma_terminate_all(struct dma_chan *c) return 0; } +static void stm32_dma_synchronize(struct dma_chan *c) +{ + struct stm32_dma_chan *chan = to_stm32_dma_chan(c); + + vchan_synchronize(&chan->vchan); +} + static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) { struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); @@ -1066,6 +1073,7 @@ static int stm32_dma_probe(struct platform_device *pdev) dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic; dd->device_config = stm32_dma_slave_config; dd->device_terminate_all = stm32_dma_terminate_all; + dd->device_synchronize = stm32_dma_synchronize; dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); From 276b0046ff7765c1d42ed48c67b4b5f3b50ea461 Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Tue, 13 Dec 2016 14:40:51 +0100 Subject: [PATCH 0074/1587] dmaengine: stm32-dma: Add max_burst support This patch sets the max_burst value supported by the STM32 DMA Signed-off-by: M'boumba Cedric Madianga Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 53b2ee79cc0e..fc9738e0f3a3 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -114,6 +114,7 @@ #define STM32_DMA_MAX_CHANNELS 0x08 #define STM32_DMA_MAX_REQUEST_ID 0x08 #define STM32_DMA_MAX_DATA_PARAM 0x03 +#define STM32_DMA_MAX_BURST 16 enum stm32_dma_width { STM32_DMA_BYTE, @@ -1082,6 +1083,7 @@ static int stm32_dma_probe(struct platform_device *pdev) BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + dd->max_burst = STM32_DMA_MAX_BURST; dd->dev = &pdev->dev; INIT_LIST_HEAD(&dd->channels); From 99e4f67508e1dd51e21ebae2150c6e4f4eae068b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 27 Dec 2016 09:19:59 -0800 Subject: [PATCH 0075/1587] pinctrl: core: Use delayed work for hogs Having the pin control framework call pin controller functions before it's probe has finished is not nice as the pin controller device driver does not yet have struct pinctrl_dev handle. Let's fix this issue by adding deferred work for late init. This is needed to be able to add pinctrl generic helper functions that expect to know struct pinctrl_dev handle. Note that we now need to call create_pinctrl() directly as we don't want to add the pin controller to the list of controllers until the hogs are claimed. We also need to pass the pinctrl_dev to the device tree parser functions as they otherwise won't find the right controller at this point. Signed-off-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 90 +++++++++++++++++++++++------------- drivers/pinctrl/core.h | 2 + drivers/pinctrl/devicetree.c | 28 +++++++++-- drivers/pinctrl/devicetree.h | 12 ++++- 4 files changed, 93 insertions(+), 39 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index fb38e208f32d..d02e8def9506 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -720,7 +720,8 @@ static struct pinctrl_state *create_state(struct pinctrl *p, return state; } -static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) +static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev, + struct pinctrl_map const *map) { struct pinctrl_state *state; struct pinctrl_setting *setting; @@ -744,7 +745,11 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) setting->type = map->type; - setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); + if (pctldev) + setting->pctldev = pctldev; + else + setting->pctldev = + get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (setting->pctldev == NULL) { kfree(setting); /* Do not defer probing of hogs (circular loop) */ @@ -800,7 +805,8 @@ static struct pinctrl *find_pinctrl(struct device *dev) static void pinctrl_free(struct pinctrl *p, bool inlist); -static struct pinctrl *create_pinctrl(struct device *dev) +static struct pinctrl *create_pinctrl(struct device *dev, + struct pinctrl_dev *pctldev) { struct pinctrl *p; const char *devname; @@ -823,7 +829,7 @@ static struct pinctrl *create_pinctrl(struct device *dev) INIT_LIST_HEAD(&p->states); INIT_LIST_HEAD(&p->dt_maps); - ret = pinctrl_dt_to_map(p); + ret = pinctrl_dt_to_map(p, pctldev); if (ret < 0) { kfree(p); return ERR_PTR(ret); @@ -838,7 +844,7 @@ static struct pinctrl *create_pinctrl(struct device *dev) if (strcmp(map->dev_name, devname)) continue; - ret = add_setting(p, map); + ret = add_setting(p, pctldev, map); /* * At this point the adding of a setting may: * @@ -899,7 +905,7 @@ struct pinctrl *pinctrl_get(struct device *dev) return p; } - return create_pinctrl(dev); + return create_pinctrl(dev, NULL); } EXPORT_SYMBOL_GPL(pinctrl_get); @@ -1737,6 +1743,46 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev) return 0; } +/** + * pinctrl_late_init() - finish pin controller device registration + * @work: work struct + */ +static void pinctrl_late_init(struct work_struct *work) +{ + struct pinctrl_dev *pctldev; + + pctldev = container_of(work, struct pinctrl_dev, late_init.work); + + pctldev->p = create_pinctrl(pctldev->dev, pctldev); + if (!IS_ERR(pctldev->p)) { + kref_get(&pctldev->p->users); + pctldev->hog_default = + pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT); + if (IS_ERR(pctldev->hog_default)) { + dev_dbg(pctldev->dev, + "failed to lookup the default state\n"); + } else { + if (pinctrl_select_state(pctldev->p, + pctldev->hog_default)) + dev_err(pctldev->dev, + "failed to select default state\n"); + } + + pctldev->hog_sleep = + pinctrl_lookup_state(pctldev->p, + PINCTRL_STATE_SLEEP); + if (IS_ERR(pctldev->hog_sleep)) + dev_dbg(pctldev->dev, + "failed to lookup the sleep state\n"); + } + + mutex_lock(&pinctrldev_list_mutex); + list_add_tail(&pctldev->node, &pinctrldev_list); + mutex_unlock(&pinctrldev_list_mutex); + + pinctrl_init_device_debugfs(pctldev); +} + /** * pinctrl_register() - register a pin controller device * @pctldesc: descriptor for this pin controller @@ -1766,6 +1812,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, pctldev->driver_data = driver_data; INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); INIT_LIST_HEAD(&pctldev->gpio_ranges); + INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init); pctldev->dev = dev; mutex_init(&pctldev->mutex); @@ -1800,32 +1847,10 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, goto out_err; } - mutex_lock(&pinctrldev_list_mutex); - list_add_tail(&pctldev->node, &pinctrldev_list); - mutex_unlock(&pinctrldev_list_mutex); - - pctldev->p = pinctrl_get(pctldev->dev); - - if (!IS_ERR(pctldev->p)) { - pctldev->hog_default = - pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT); - if (IS_ERR(pctldev->hog_default)) { - dev_dbg(dev, "failed to lookup the default state\n"); - } else { - if (pinctrl_select_state(pctldev->p, - pctldev->hog_default)) - dev_err(dev, - "failed to select default state\n"); - } - - pctldev->hog_sleep = - pinctrl_lookup_state(pctldev->p, - PINCTRL_STATE_SLEEP); - if (IS_ERR(pctldev->hog_sleep)) - dev_dbg(dev, "failed to lookup the sleep state\n"); - } - - pinctrl_init_device_debugfs(pctldev); + if (pinctrl_dt_has_hogs(pctldev)) + schedule_delayed_work(&pctldev->late_init, 0); + else + pinctrl_late_init(&pctldev->late_init.work); return pctldev; @@ -1848,6 +1873,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) if (pctldev == NULL) return; + cancel_delayed_work_sync(&pctldev->late_init); mutex_lock(&pctldev->mutex); pinctrl_remove_device_debugfs(pctldev); mutex_unlock(&pctldev->mutex); diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 747c423c11f3..722b2579166d 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -33,6 +33,7 @@ struct pinctrl_gpio_range; * @p: result of pinctrl_get() for this device * @hog_default: default state for pins hogged by this device * @hog_sleep: sleep state for pins hogged by this device + * @late_init: delayed work for pin controller to finish registration * @mutex: mutex taken on each pin controller specific action * @device_root: debugfs root for this device */ @@ -47,6 +48,7 @@ struct pinctrl_dev { struct pinctrl *p; struct pinctrl_state *hog_default; struct pinctrl_state *hog_sleep; + struct delayed_work late_init; struct mutex mutex; #ifdef CONFIG_DEBUG_FS struct dentry *device_root; diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 260908480075..e082bddad83a 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -100,11 +100,12 @@ struct pinctrl_dev *of_pinctrl_get(struct device_node *np) return get_pinctrl_dev_from_of_node(np); } -static int dt_to_map_one_config(struct pinctrl *p, const char *statename, +static int dt_to_map_one_config(struct pinctrl *p, + struct pinctrl_dev *pctldev, + const char *statename, struct device_node *np_config) { struct device_node *np_pctldev; - struct pinctrl_dev *pctldev; const struct pinctrl_ops *ops; int ret; struct pinctrl_map *map; @@ -121,7 +122,8 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename, /* OK let's just assume this will appear later then */ return -EPROBE_DEFER; } - pctldev = get_pinctrl_dev_from_of_node(np_pctldev); + if (!pctldev) + pctldev = get_pinctrl_dev_from_of_node(np_pctldev); if (pctldev) break; /* Do not defer probing of hogs (circular loop) */ @@ -166,7 +168,22 @@ static int dt_remember_dummy_state(struct pinctrl *p, const char *statename) return dt_remember_or_free_map(p, statename, NULL, map, 1); } -int pinctrl_dt_to_map(struct pinctrl *p) +bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev) +{ + struct device_node *np; + struct property *prop; + int size; + + np = pctldev->dev->of_node; + if (!np) + return false; + + prop = of_find_property(np, "pinctrl-0", &size); + + return prop ? true : false; +} + +int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev) { struct device_node *np = p->dev->of_node; int state, ret; @@ -233,7 +250,8 @@ int pinctrl_dt_to_map(struct pinctrl *p) } /* Parse the node */ - ret = dt_to_map_one_config(p, statename, np_config); + ret = dt_to_map_one_config(p, pctldev, statename, + np_config); of_node_put(np_config); if (ret < 0) goto err; diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h index c2d1a5505850..43d8d19aa5ee 100644 --- a/drivers/pinctrl/devicetree.h +++ b/drivers/pinctrl/devicetree.h @@ -20,8 +20,10 @@ struct of_phandle_args; #ifdef CONFIG_OF +bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev); + void pinctrl_dt_free_maps(struct pinctrl *p); -int pinctrl_dt_to_map(struct pinctrl *p); +int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev); int pinctrl_count_index_with_args(const struct device_node *np, const char *list_name); @@ -32,7 +34,13 @@ int pinctrl_parse_index_with_args(const struct device_node *np, #else -static inline int pinctrl_dt_to_map(struct pinctrl *p) +static inline bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev) +{ + return false; +} + +static inline int pinctrl_dt_to_map(struct pinctrl *p, + struct pinctrl_dev *pctldev) { return 0; } From 2d22e5b006d1c37dc4df012bd13b75e581fa6aa2 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 30 Dec 2016 14:44:18 +0100 Subject: [PATCH 0076/1587] pinctrl: add some comments to the hog/late init code It confused me a bit so it may confuse others. Make it crystal clear what is going on here for any future readers. Cc: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index d02e8def9506..a9e3a75fb67d 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1753,6 +1753,12 @@ static void pinctrl_late_init(struct work_struct *work) pctldev = container_of(work, struct pinctrl_dev, late_init.work); + /* + * If the pin controller does NOT have hogs, this will report an + * error and we skip over this entire branch. This is why we can + * call this function directly when we do not have hogs on the + * device. + */ pctldev->p = create_pinctrl(pctldev->dev, pctldev); if (!IS_ERR(pctldev->p)) { kref_get(&pctldev->p->users); @@ -1847,6 +1853,12 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, goto out_err; } + /* + * If the device has hogs we want the probe() function of the driver + * to complete before we go in and hog them and add the pin controller + * to the list of controllers. If it has no hogs, we can just complete + * the registration immediately. + */ if (pinctrl_dt_has_hogs(pctldev)) schedule_delayed_work(&pctldev->late_init, 0); else From c7059c5ac70aea194b07b2d811df433eb0ca81b5 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 27 Dec 2016 09:20:00 -0800 Subject: [PATCH 0077/1587] pinctrl: core: Add generic pinctrl functions for managing groups We can add generic helpers for pin group handling for cases where the pin controller driver does not need to use static arrays. Signed-off-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 3 + drivers/pinctrl/core.c | 178 ++++++++++++++++++++++++++++++++++++++++ drivers/pinctrl/core.h | 47 +++++++++++ 3 files changed, 228 insertions(+) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 54044a8ecbd7..b986998409d1 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -8,6 +8,9 @@ config PINCTRL menu "Pin controllers" depends on PINCTRL +config GENERIC_PINCTRL + bool + config PINMUX bool "Support pin multiplexing controllers" if COMPILE_TEST diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index a9e3a75fb67d..7b7d706f869c 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -540,6 +540,182 @@ void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); +#ifdef CONFIG_GENERIC_PINCTRL + +/** + * pinctrl_generic_get_group_count() - returns the number of pin groups + * @pctldev: pin controller device + */ +int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev) +{ + return pctldev->num_groups; +} +EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_count); + +/** + * pinctrl_generic_get_group_name() - returns the name of a pin group + * @pctldev: pin controller device + * @selector: group number + */ +const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct group_desc *group; + + group = radix_tree_lookup(&pctldev->pin_group_tree, + selector); + if (!group) + return NULL; + + return group->name; +} +EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_name); + +/** + * pinctrl_generic_get_group_pins() - gets the pin group pins + * @pctldev: pin controller device + * @selector: group number + * @pins: pins in the group + * @num_pins: number of pins in the group + */ +int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct group_desc *group; + + group = radix_tree_lookup(&pctldev->pin_group_tree, + selector); + if (!group) { + dev_err(pctldev->dev, "%s could not find pingroup%i\n", + __func__, selector); + return -EINVAL; + } + + *pins = group->pins; + *num_pins = group->num_pins; + + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_pins); + +/** + * pinctrl_generic_get_group() - returns a pin group based on the number + * @pctldev: pin controller device + * @gselector: group number + */ +struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct group_desc *group; + + group = radix_tree_lookup(&pctldev->pin_group_tree, + selector); + if (!group) + return NULL; + + return group; +} +EXPORT_SYMBOL_GPL(pinctrl_generic_get_group); + +/** + * pinctrl_generic_add_group() - adds a new pin group + * @pctldev: pin controller device + * @name: name of the pin group + * @pins: pins in the pin group + * @num_pins: number of pins in the pin group + * @data: pin controller driver specific data + * + * Note that the caller must take care of locking. + */ +int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name, + int *pins, int num_pins, void *data) +{ + struct group_desc *group; + + group = devm_kzalloc(pctldev->dev, sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + + group->name = name; + group->pins = pins; + group->num_pins = num_pins; + group->data = data; + + radix_tree_insert(&pctldev->pin_group_tree, pctldev->num_groups, + group); + + pctldev->num_groups++; + + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_generic_add_group); + +/** + * pinctrl_generic_remove_group() - removes a numbered pin group + * @pctldev: pin controller device + * @selector: group number + * + * Note that the caller must take care of locking. + */ +int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct group_desc *group; + + group = radix_tree_lookup(&pctldev->pin_group_tree, + selector); + if (!group) + return -ENOENT; + + radix_tree_delete(&pctldev->pin_group_tree, selector); + devm_kfree(pctldev->dev, group); + + pctldev->num_groups--; + + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_generic_remove_group); + +/** + * pinctrl_generic_free_groups() - removes all pin groups + * @pctldev: pin controller device + * + * Note that the caller must take care of locking. + */ +static void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev) +{ + struct radix_tree_iter iter; + struct group_desc *group; + unsigned long *indices; + void **slot; + int i = 0; + + indices = devm_kzalloc(pctldev->dev, sizeof(*indices) * + pctldev->num_groups, GFP_KERNEL); + if (!indices) + return; + + radix_tree_for_each_slot(slot, &pctldev->pin_group_tree, &iter, 0) + indices[i++] = iter.index; + + for (i = 0; i < pctldev->num_groups; i++) { + group = radix_tree_lookup(&pctldev->pin_group_tree, + indices[i]); + radix_tree_delete(&pctldev->pin_group_tree, indices[i]); + devm_kfree(pctldev->dev, group); + } + + pctldev->num_groups = 0; +} + +#else +static inline void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev) +{ +} +#endif /* CONFIG_GENERIC_PINCTRL */ + /** * pinctrl_get_group_selector() - returns the group selector for a group * @pctldev: the pin controller handling the group @@ -1817,6 +1993,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, pctldev->desc = pctldesc; pctldev->driver_data = driver_data; INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); + INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL); INIT_LIST_HEAD(&pctldev->gpio_ranges); INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init); pctldev->dev = dev; @@ -1897,6 +2074,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) mutex_lock(&pctldev->mutex); /* TODO: check that no pinmuxes are still active? */ list_del(&pctldev->node); + pinctrl_generic_free_groups(pctldev); /* Destroy descriptor tree */ pinctrl_free_pindescs(pctldev, pctldev->desc->pins, pctldev->desc->npins); diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 722b2579166d..af98b6313902 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -24,6 +24,8 @@ struct pinctrl_gpio_range; * controller * @pin_desc_tree: each pin descriptor for this pin controller is stored in * this radix tree + * @pin_group_tree: optionally each pin group can be stored in this radix tree + * @num_groups: optionally number of groups can be kept here * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller, * ranges are added to this list at runtime * @dev: the device entry for this pin controller @@ -41,6 +43,8 @@ struct pinctrl_dev { struct list_head node; struct pinctrl_desc *desc; struct radix_tree_root pin_desc_tree; + struct radix_tree_root pin_group_tree; + unsigned int num_groups; struct list_head gpio_ranges; struct device *dev; struct module *owner; @@ -161,6 +165,20 @@ struct pin_desc { #endif }; +/** + * struct group_desc - generic pin group descriptor + * @name: name of the pin group + * @pins: array of pins that belong to the group + * @num_pins: number of pins in the group + * @data: pin controller driver specific data + */ +struct group_desc { + const char *name; + int *pins; + int num_pins; + void *data; +}; + /** * struct pinctrl_maps - a list item containing part of the mapping table * @node: mapping table list node @@ -173,6 +191,35 @@ struct pinctrl_maps { unsigned num_maps; }; +#ifdef CONFIG_GENERIC_PINCTRL + +int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev); + +const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group_selector, + const unsigned int **pins, + unsigned int *npins); + +struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name, + int *gpins, int ngpins, void *data); + +int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +static inline int +pinctrl_generic_remove_last_group(struct pinctrl_dev *pctldev) +{ + return pinctrl_generic_remove_group(pctldev, pctldev->num_groups - 1); +} + +#endif /* CONFIG_GENERIC_PINCTRL */ + struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np); int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); From c033a718f615b6b3ddc83ce3e0a217c30bd09cb5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 30 Dec 2016 15:04:43 +0100 Subject: [PATCH 0078/1587] pinctrl: stricten up generic group code Rename the symbol PINCTRL_GENERIC to PINCTRL_GENERIC_GROUPS since it all pertains to groups. Replace everywhere. ifdef out the radix tree and the struct when not using the generic groups. Cc: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 2 +- drivers/pinctrl/core.c | 6 ++++-- drivers/pinctrl/core.h | 32 +++++++++++++++++--------------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index b986998409d1..add257f80d76 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -8,7 +8,7 @@ config PINCTRL menu "Pin controllers" depends on PINCTRL -config GENERIC_PINCTRL +config GENERIC_PINCTRL_GROUPS bool config PINMUX diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 7b7d706f869c..736149d3a33d 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -540,7 +540,7 @@ void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); -#ifdef CONFIG_GENERIC_PINCTRL +#ifdef CONFIG_GENERIC_PINCTRL_GROUPS /** * pinctrl_generic_get_group_count() - returns the number of pin groups @@ -714,7 +714,7 @@ static void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev) static inline void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev) { } -#endif /* CONFIG_GENERIC_PINCTRL */ +#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */ /** * pinctrl_get_group_selector() - returns the group selector for a group @@ -1993,7 +1993,9 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, pctldev->desc = pctldesc; pctldev->driver_data = driver_data; INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); +#ifdef CONFIG_GENERIC_PINCTRL_GROUPS INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL); +#endif INIT_LIST_HEAD(&pctldev->gpio_ranges); INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init); pctldev->dev = dev; diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index af98b6313902..b04c59bf9701 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -43,8 +43,10 @@ struct pinctrl_dev { struct list_head node; struct pinctrl_desc *desc; struct radix_tree_root pin_desc_tree; +#ifdef CONFIG_GENERIC_PINCTRL_GROUPS struct radix_tree_root pin_group_tree; unsigned int num_groups; +#endif struct list_head gpio_ranges; struct device *dev; struct module *owner; @@ -165,6 +167,20 @@ struct pin_desc { #endif }; +/** + * struct pinctrl_maps - a list item containing part of the mapping table + * @node: mapping table list node + * @maps: array of mapping table entries + * @num_maps: the number of entries in @maps + */ +struct pinctrl_maps { + struct list_head node; + struct pinctrl_map const *maps; + unsigned num_maps; +}; + +#ifdef CONFIG_GENERIC_PINCTRL_GROUPS + /** * struct group_desc - generic pin group descriptor * @name: name of the pin group @@ -179,20 +195,6 @@ struct group_desc { void *data; }; -/** - * struct pinctrl_maps - a list item containing part of the mapping table - * @node: mapping table list node - * @maps: array of mapping table entries - * @num_maps: the number of entries in @maps - */ -struct pinctrl_maps { - struct list_head node; - struct pinctrl_map const *maps; - unsigned num_maps; -}; - -#ifdef CONFIG_GENERIC_PINCTRL - int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev); const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev, @@ -218,7 +220,7 @@ pinctrl_generic_remove_last_group(struct pinctrl_dev *pctldev) return pinctrl_generic_remove_group(pctldev, pctldev->num_groups - 1); } -#endif /* CONFIG_GENERIC_PINCTRL */ +#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */ struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np); From a76edc89b100e4fefb2a5c00cd8cd557437659e7 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 27 Dec 2016 09:20:01 -0800 Subject: [PATCH 0079/1587] pinctrl: core: Add generic pinctrl functions for managing groups We can add generic helpers for function handling for cases where the pin controller driver does not need to use static arrays. Signed-off-by: Tony Lindgren [Renamed the Kconfig item and moved things around] Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 4 + drivers/pinctrl/core.c | 4 + drivers/pinctrl/core.h | 6 ++ drivers/pinctrl/pinmux.c | 173 +++++++++++++++++++++++++++++++++++++++ drivers/pinctrl/pinmux.h | 56 +++++++++++++ 5 files changed, 243 insertions(+) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index add257f80d76..7e964284b2c9 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -14,6 +14,10 @@ config GENERIC_PINCTRL_GROUPS config PINMUX bool "Support pin multiplexing controllers" if COMPILE_TEST +config GENERIC_PINMUX_FUNCTIONS + bool + select PINMUX + config PINCONF bool "Support pin configuration controllers" if COMPILE_TEST diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 736149d3a33d..d311d73852a0 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1995,6 +1995,9 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); #ifdef CONFIG_GENERIC_PINCTRL_GROUPS INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL); +#endif +#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS + INIT_RADIX_TREE(&pctldev->pin_function_tree, GFP_KERNEL); #endif INIT_LIST_HEAD(&pctldev->gpio_ranges); INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init); @@ -2076,6 +2079,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) mutex_lock(&pctldev->mutex); /* TODO: check that no pinmuxes are still active? */ list_del(&pctldev->node); + pinmux_generic_free_functions(pctldev); pinctrl_generic_free_groups(pctldev); /* Destroy descriptor tree */ pinctrl_free_pindescs(pctldev, pctldev->desc->pins, diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index b04c59bf9701..ad812a2d7248 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -26,6 +26,8 @@ struct pinctrl_gpio_range; * this radix tree * @pin_group_tree: optionally each pin group can be stored in this radix tree * @num_groups: optionally number of groups can be kept here + * @pin_function_tree: optionally each function can be stored in this radix tree + * @num_functions: optionally number of functions can be kept here * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller, * ranges are added to this list at runtime * @dev: the device entry for this pin controller @@ -46,6 +48,10 @@ struct pinctrl_dev { #ifdef CONFIG_GENERIC_PINCTRL_GROUPS struct radix_tree_root pin_group_tree; unsigned int num_groups; +#endif +#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS + struct radix_tree_root pin_function_tree; + unsigned int num_functions; #endif struct list_head gpio_ranges; struct device *dev; diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 9373146f3afc..29ad3151abec 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -682,3 +682,176 @@ void pinmux_init_device_debugfs(struct dentry *devroot, } #endif /* CONFIG_DEBUG_FS */ + +#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS + +/** + * pinmux_generic_get_function_count() - returns number of functions + * @pctldev: pin controller device + */ +int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev) +{ + return pctldev->num_functions; +} +EXPORT_SYMBOL_GPL(pinmux_generic_get_function_count); + +/** + * pinmux_generic_get_function_name() - returns the function name + * @pctldev: pin controller device + * @selector: function number + */ +const char * +pinmux_generic_get_function_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct function_desc *function; + + function = radix_tree_lookup(&pctldev->pin_function_tree, + selector); + if (!function) + return NULL; + + return function->name; +} +EXPORT_SYMBOL_GPL(pinmux_generic_get_function_name); + +/** + * pinmux_generic_get_function_groups() - gets the function groups + * @pctldev: pin controller device + * @selector: function number + * @groups: array of pin groups + * @num_groups: number of pin groups + */ +int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct function_desc *function; + + function = radix_tree_lookup(&pctldev->pin_function_tree, + selector); + if (!function) { + dev_err(pctldev->dev, "%s could not find function%i\n", + __func__, selector); + return -EINVAL; + } + *groups = function->group_names; + *num_groups = function->num_group_names; + + return 0; +} +EXPORT_SYMBOL_GPL(pinmux_generic_get_function_groups); + +/** + * pinmux_generic_get_function() - returns a function based on the number + * @pctldev: pin controller device + * @group_selector: function number + */ +struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct function_desc *function; + + function = radix_tree_lookup(&pctldev->pin_function_tree, + selector); + if (!function) + return NULL; + + return function; +} +EXPORT_SYMBOL_GPL(pinmux_generic_get_function); + +/** + * pinmux_generic_get_function_groups() - gets the function groups + * @pctldev: pin controller device + * @name: name of the function + * @groups: array of pin groups + * @num_groups: number of pin groups + * @data: pin controller driver specific data + */ +int pinmux_generic_add_function(struct pinctrl_dev *pctldev, + const char *name, + const char **groups, + const unsigned int num_groups, + void *data) +{ + struct function_desc *function; + + function = devm_kzalloc(pctldev->dev, sizeof(*function), GFP_KERNEL); + if (!function) + return -ENOMEM; + + function->name = name; + function->group_names = groups; + function->num_group_names = num_groups; + function->data = data; + + radix_tree_insert(&pctldev->pin_function_tree, pctldev->num_functions, + function); + + pctldev->num_functions++; + + return 0; +} +EXPORT_SYMBOL_GPL(pinmux_generic_add_function); + +/** + * pinmux_generic_remove_function() - removes a numbered function + * @pctldev: pin controller device + * @selector: function number + * + * Note that the caller must take care of locking. + */ +int pinmux_generic_remove_function(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct function_desc *function; + + function = radix_tree_lookup(&pctldev->pin_function_tree, + selector); + if (!function) + return -ENOENT; + + radix_tree_delete(&pctldev->pin_function_tree, selector); + devm_kfree(pctldev->dev, function); + + pctldev->num_functions--; + + return 0; +} +EXPORT_SYMBOL_GPL(pinmux_generic_remove_function); + +/** + * pinmux_generic_free_functions() - removes all functions + * @pctldev: pin controller device + * + * Note that the caller must take care of locking. + */ +void pinmux_generic_free_functions(struct pinctrl_dev *pctldev) +{ + struct radix_tree_iter iter; + struct function_desc *function; + unsigned long *indices; + void **slot; + int i = 0; + + indices = devm_kzalloc(pctldev->dev, sizeof(*indices) * + pctldev->num_functions, GFP_KERNEL); + if (!indices) + return; + + radix_tree_for_each_slot(slot, &pctldev->pin_function_tree, &iter, 0) + indices[i++] = iter.index; + + for (i = 0; i < pctldev->num_functions; i++) { + function = radix_tree_lookup(&pctldev->pin_function_tree, + indices[i]); + radix_tree_delete(&pctldev->pin_function_tree, indices[i]); + devm_kfree(pctldev->dev, function); + } + + pctldev->num_functions = 0; +} + +#endif /* CONFIG_GENERIC_PINMUX_FUNCTIONS */ diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h index d1a98b1c9fce..248d8ea30e26 100644 --- a/drivers/pinctrl/pinmux.h +++ b/drivers/pinctrl/pinmux.h @@ -111,3 +111,59 @@ static inline void pinmux_init_device_debugfs(struct dentry *devroot, } #endif + +#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS + +/** + * struct function_desc - generic function descriptor + * @name: name of the function + * @group_names: array of pin group names + * @num_group_names: number of pin group names + * @data: pin controller driver specific data + */ +struct function_desc { + const char *name; + const char **group_names; + int num_group_names; + void *data; +}; + +int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev); + +const char * +pinmux_generic_get_function_name(struct pinctrl_dev *pctldev, + unsigned int selector); + +int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned * const num_groups); + +struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev, + unsigned int selector); + +int pinmux_generic_add_function(struct pinctrl_dev *pctldev, + const char *name, + const char **groups, + unsigned const num_groups, + void *data); + +int pinmux_generic_remove_function(struct pinctrl_dev *pctldev, + unsigned int selector); + +static inline int +pinmux_generic_remove_last_function(struct pinctrl_dev *pctldev) +{ + return pinmux_generic_remove_function(pctldev, + pctldev->num_functions - 1); +} + +void pinmux_generic_free_functions(struct pinctrl_dev *pctldev); + +#else + +static inline void pinmux_generic_free_functions(struct pinctrl_dev *pctldev) +{ +} + +#endif /* CONFIG_GENERIC_PINMUX_FUNCTIONS */ From caeb774ea3b1bc25dc2f24681c27543aba6ca7ae Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 27 Dec 2016 09:20:02 -0800 Subject: [PATCH 0080/1587] pinctrl: single: Use generic pinctrl helpers for managing groups We can now drop the driver specific code for managing groups. Signed-off-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 2 +- drivers/pinctrl/pinctrl-single.c | 156 +++---------------------------- 2 files changed, 12 insertions(+), 146 deletions(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7e964284b2c9..d2fbcea98205 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -166,8 +166,8 @@ config PINCTRL_ROCKCHIP config PINCTRL_SINGLE tristate "One-register-per-pin type device tree based pinctrl driver" depends on OF + select GENERIC_PINCTRL_GROUPS select PINMUX - select PINCONF select GENERIC_PINCONF help This selects the device tree based generic pinctrl driver. diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 25edadf75b43..5e7a37ddef8e 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -37,22 +37,6 @@ #define DRIVER_NAME "pinctrl-single" #define PCS_OFF_DISABLED ~0U -/** - * struct pcs_pingroup - pingroups for a function - * @np: pingroup device node pointer - * @name: pingroup name - * @gpins: array of the pins in the group - * @ngpins: number of pins in the group - * @node: list node - */ -struct pcs_pingroup { - struct device_node *np; - const char *name; - int *gpins; - int ngpins; - struct list_head node; -}; - /** * struct pcs_func_vals - mux function register offset and value pair * @reg: register virtual address @@ -176,15 +160,12 @@ struct pcs_soc_data { * @bits_per_mux: number of bits per mux * @bits_per_pin: number of bits per pin * @pins: physical pins on the SoC - * @pgtree: pingroup index radix tree * @ftree: function index radix tree - * @pingroups: list of pingroups * @functions: list of functions * @gpiofuncs: list of gpio functions * @irqs: list of interrupt registers * @chip: chip container for this instance * @domain: IRQ domain for this instance - * @ngroups: number of pingroups * @nfuncs: number of functions * @desc: pin controller descriptor * @read: register read function to use @@ -213,15 +194,12 @@ struct pcs_device { bool bits_per_mux; unsigned bits_per_pin; struct pcs_data pins; - struct radix_tree_root pgtree; struct radix_tree_root ftree; - struct list_head pingroups; struct list_head functions; struct list_head gpiofuncs; struct list_head irqs; struct irq_chip chip; struct irq_domain *domain; - unsigned ngroups; unsigned nfuncs; struct pinctrl_desc desc; unsigned (*read)(void __iomem *reg); @@ -288,54 +266,6 @@ static void __maybe_unused pcs_writel(unsigned val, void __iomem *reg) writel(val, reg); } -static int pcs_get_groups_count(struct pinctrl_dev *pctldev) -{ - struct pcs_device *pcs; - - pcs = pinctrl_dev_get_drvdata(pctldev); - - return pcs->ngroups; -} - -static const char *pcs_get_group_name(struct pinctrl_dev *pctldev, - unsigned gselector) -{ - struct pcs_device *pcs; - struct pcs_pingroup *group; - - pcs = pinctrl_dev_get_drvdata(pctldev); - group = radix_tree_lookup(&pcs->pgtree, gselector); - if (!group) { - dev_err(pcs->dev, "%s could not find pingroup%i\n", - __func__, gselector); - return NULL; - } - - return group->name; -} - -static int pcs_get_group_pins(struct pinctrl_dev *pctldev, - unsigned gselector, - const unsigned **pins, - unsigned *npins) -{ - struct pcs_device *pcs; - struct pcs_pingroup *group; - - pcs = pinctrl_dev_get_drvdata(pctldev); - group = radix_tree_lookup(&pcs->pgtree, gselector); - if (!group) { - dev_err(pcs->dev, "%s could not find pingroup%i\n", - __func__, gselector); - return -EINVAL; - } - - *pins = group->gpins; - *npins = group->ngpins; - - return 0; -} - static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin) @@ -369,9 +299,9 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **map, unsigned *num_maps); static const struct pinctrl_ops pcs_pinctrl_ops = { - .get_groups_count = pcs_get_groups_count, - .get_group_name = pcs_get_group_name, - .get_group_pins = pcs_get_group_pins, + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, .pin_dbg_show = pcs_pin_dbg_show, .dt_node_to_map = pcs_dt_node_to_map, .dt_free_map = pcs_dt_free_map, @@ -685,7 +615,7 @@ static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev, unsigned npins, old = 0; int i, ret; - ret = pcs_get_group_pins(pctldev, group, &pins, &npins); + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); if (ret) return ret; for (i = 0; i < npins; i++) { @@ -707,7 +637,7 @@ static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev, unsigned npins; int i, ret; - ret = pcs_get_group_pins(pctldev, group, &pins, &npins); + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); if (ret) return ret; for (i = 0; i < npins; i++) { @@ -896,40 +826,6 @@ static void pcs_remove_function(struct pcs_device *pcs, mutex_unlock(&pcs->mutex); } -/** - * pcs_add_pingroup() - add a pingroup to the pingroup list - * @pcs: pcs driver instance - * @np: device node of the mux entry - * @name: name of the pingroup - * @gpins: array of the pins that belong to the group - * @ngpins: number of pins in the group - */ -static int pcs_add_pingroup(struct pcs_device *pcs, - struct device_node *np, - const char *name, - int *gpins, - int ngpins) -{ - struct pcs_pingroup *pingroup; - - pingroup = devm_kzalloc(pcs->dev, sizeof(*pingroup), GFP_KERNEL); - if (!pingroup) - return -ENOMEM; - - pingroup->name = name; - pingroup->np = np; - pingroup->gpins = gpins; - pingroup->ngpins = ngpins; - - mutex_lock(&pcs->mutex); - list_add_tail(&pingroup->node, &pcs->pingroups); - radix_tree_insert(&pcs->pgtree, pcs->ngroups, pingroup); - pcs->ngroups++; - mutex_unlock(&pcs->mutex); - - return 0; -} - /** * pcs_get_pin_by_offset() - get a pin index based on the register offset * @pcs: pcs driver instance @@ -1100,10 +996,9 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np, return 0; } -static void pcs_free_pingroups(struct pcs_device *pcs); - /** * smux_parse_one_pinctrl_entry() - parses a device tree mux entry + * @pctldev: pin controller device * @pcs: pinctrl driver instance * @np: device node of the mux entry * @map: map entry @@ -1186,7 +1081,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, goto free_pins; } - res = pcs_add_pingroup(pcs, np, np->name, pins, found); + res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs); if (res < 0) goto free_function; @@ -1205,7 +1100,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, return 0; free_pingroups: - pcs_free_pingroups(pcs); + pinctrl_generic_remove_last_group(pcs->pctl); *num_maps = 1; free_function: pcs_remove_function(pcs, function); @@ -1320,7 +1215,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, goto free_pins; } - res = pcs_add_pingroup(pcs, np, np->name, pins, found); + res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs); if (res < 0) goto free_function; @@ -1337,7 +1232,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, return 0; free_pingroups: - pcs_free_pingroups(pcs); + pinctrl_generic_remove_last_group(pcs->pctl); *num_maps = 1; free_function: pcs_remove_function(pcs, function); @@ -1435,33 +1330,6 @@ static void pcs_free_funcs(struct pcs_device *pcs) mutex_unlock(&pcs->mutex); } -/** - * pcs_free_pingroups() - free memory used by pingroups - * @pcs: pcs driver instance - */ -static void pcs_free_pingroups(struct pcs_device *pcs) -{ - struct list_head *pos, *tmp; - int i; - - mutex_lock(&pcs->mutex); - for (i = 0; i < pcs->ngroups; i++) { - struct pcs_pingroup *pingroup; - - pingroup = radix_tree_lookup(&pcs->pgtree, i); - if (!pingroup) - continue; - radix_tree_delete(&pcs->pgtree, i); - } - list_for_each_safe(pos, tmp, &pcs->pingroups) { - struct pcs_pingroup *pingroup; - - pingroup = list_entry(pos, struct pcs_pingroup, node); - list_del(&pingroup->node); - } - mutex_unlock(&pcs->mutex); -} - /** * pcs_irq_free() - free interrupt * @pcs: pcs driver instance @@ -1491,7 +1359,7 @@ static void pcs_free_resources(struct pcs_device *pcs) pcs_irq_free(pcs); pinctrl_unregister(pcs->pctl); pcs_free_funcs(pcs); - pcs_free_pingroups(pcs); + #if IS_BUILTIN(CONFIG_PINCTRL_SINGLE) if (pcs->missing_nr_pinctrl_cells) of_remove_property(pcs->np, pcs->missing_nr_pinctrl_cells); @@ -1885,7 +1753,6 @@ static int pcs_probe(struct platform_device *pdev) pcs->np = np; raw_spin_lock_init(&pcs->lock); mutex_init(&pcs->mutex); - INIT_LIST_HEAD(&pcs->pingroups); INIT_LIST_HEAD(&pcs->functions); INIT_LIST_HEAD(&pcs->gpiofuncs); soc = match->data; @@ -1947,7 +1814,6 @@ static int pcs_probe(struct platform_device *pdev) return -ENODEV; } - INIT_RADIX_TREE(&pcs->pgtree, GFP_KERNEL); INIT_RADIX_TREE(&pcs->ftree, GFP_KERNEL); platform_set_drvdata(pdev, pcs); From 571aec4df5b72a80f80d1e524da8fbd7ff525c98 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 27 Dec 2016 09:20:03 -0800 Subject: [PATCH 0081/1587] pinctrl: single: Use generic pinmux helpers for managing functions We can now drop the driver specific code for managing functions. Signed-off-by: Tony Lindgren [Replaces GENERIC_PINMUX with GENERIC_PINMUX_FUNCTIONS] Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 2 +- drivers/pinctrl/pinctrl-single.c | 134 +++++-------------------------- 2 files changed, 19 insertions(+), 117 deletions(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d2fbcea98205..e806f96fc8a3 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -167,7 +167,7 @@ config PINCTRL_SINGLE tristate "One-register-per-pin type device tree based pinctrl driver" depends on OF select GENERIC_PINCTRL_GROUPS - select PINMUX + select GENERIC_PINMUX_FUNCTIONS select GENERIC_PINCONF help This selects the device tree based generic pinctrl driver. diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 5e7a37ddef8e..8408263de466 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -33,6 +33,7 @@ #include "core.h" #include "devicetree.h" #include "pinconf.h" +#include "pinmux.h" #define DRIVER_NAME "pinctrl-single" #define PCS_OFF_DISABLED ~0U @@ -160,13 +161,10 @@ struct pcs_soc_data { * @bits_per_mux: number of bits per mux * @bits_per_pin: number of bits per pin * @pins: physical pins on the SoC - * @ftree: function index radix tree - * @functions: list of functions * @gpiofuncs: list of gpio functions * @irqs: list of interrupt registers * @chip: chip container for this instance * @domain: IRQ domain for this instance - * @nfuncs: number of functions * @desc: pin controller descriptor * @read: register read function to use * @write: register write function to use @@ -194,13 +192,10 @@ struct pcs_device { bool bits_per_mux; unsigned bits_per_pin; struct pcs_data pins; - struct radix_tree_root ftree; - struct list_head functions; struct list_head gpiofuncs; struct list_head irqs; struct irq_chip chip; struct irq_domain *domain; - unsigned nfuncs; struct pinctrl_desc desc; unsigned (*read)(void __iomem *reg); void (*write)(unsigned val, void __iomem *reg); @@ -307,59 +302,13 @@ static const struct pinctrl_ops pcs_pinctrl_ops = { .dt_free_map = pcs_dt_free_map, }; -static int pcs_get_functions_count(struct pinctrl_dev *pctldev) -{ - struct pcs_device *pcs; - - pcs = pinctrl_dev_get_drvdata(pctldev); - - return pcs->nfuncs; -} - -static const char *pcs_get_function_name(struct pinctrl_dev *pctldev, - unsigned fselector) -{ - struct pcs_device *pcs; - struct pcs_function *func; - - pcs = pinctrl_dev_get_drvdata(pctldev); - func = radix_tree_lookup(&pcs->ftree, fselector); - if (!func) { - dev_err(pcs->dev, "%s could not find function%i\n", - __func__, fselector); - return NULL; - } - - return func->name; -} - -static int pcs_get_function_groups(struct pinctrl_dev *pctldev, - unsigned fselector, - const char * const **groups, - unsigned * const ngroups) -{ - struct pcs_device *pcs; - struct pcs_function *func; - - pcs = pinctrl_dev_get_drvdata(pctldev); - func = radix_tree_lookup(&pcs->ftree, fselector); - if (!func) { - dev_err(pcs->dev, "%s could not find function%i\n", - __func__, fselector); - return -EINVAL; - } - *groups = func->pgnames; - *ngroups = func->npgnames; - - return 0; -} - static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin, struct pcs_function **func) { struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pin_desc *pdesc = pin_desc_get(pctldev, pin); const struct pinctrl_setting_mux *setting; + struct function_desc *function; unsigned fselector; /* If pin is not described in DTS & enabled, mux_setting is NULL. */ @@ -367,7 +316,8 @@ static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin, if (!setting) return -ENOTSUPP; fselector = setting->func; - *func = radix_tree_lookup(&pcs->ftree, fselector); + function = pinmux_generic_get_function(pctldev, fselector); + *func = function->data; if (!(*func)) { dev_err(pcs->dev, "%s could not find function%i\n", __func__, fselector); @@ -380,6 +330,7 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, unsigned group) { struct pcs_device *pcs; + struct function_desc *function; struct pcs_function *func; int i; @@ -387,7 +338,8 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, /* If function mask is null, needn't enable it. */ if (!pcs->fmask) return 0; - func = radix_tree_lookup(&pcs->ftree, fselector); + function = pinmux_generic_get_function(pctldev, fselector); + func = function->data; if (!func) return -EINVAL; @@ -445,9 +397,9 @@ static int pcs_request_gpio(struct pinctrl_dev *pctldev, } static const struct pinmux_ops pcs_pinmux_ops = { - .get_functions_count = pcs_get_functions_count, - .get_function_name = pcs_get_function_name, - .get_function_groups = pcs_get_function_groups, + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, .set_mux = pcs_set_mux, .gpio_request_enable = pcs_request_gpio, }; @@ -789,43 +741,24 @@ static struct pcs_function *pcs_add_function(struct pcs_device *pcs, unsigned npgnames) { struct pcs_function *function; + int res; function = devm_kzalloc(pcs->dev, sizeof(*function), GFP_KERNEL); if (!function) return NULL; - function->name = name; function->vals = vals; function->nvals = nvals; - function->pgnames = pgnames; - function->npgnames = npgnames; - mutex_lock(&pcs->mutex); - list_add_tail(&function->node, &pcs->functions); - radix_tree_insert(&pcs->ftree, pcs->nfuncs, function); - pcs->nfuncs++; - mutex_unlock(&pcs->mutex); + res = pinmux_generic_add_function(pcs->pctl, name, + pgnames, npgnames, + function); + if (res) + return NULL; return function; } -static void pcs_remove_function(struct pcs_device *pcs, - struct pcs_function *function) -{ - int i; - - mutex_lock(&pcs->mutex); - for (i = 0; i < pcs->nfuncs; i++) { - struct pcs_function *found; - - found = radix_tree_lookup(&pcs->ftree, i); - if (found == function) - radix_tree_delete(&pcs->ftree, i); - } - list_del(&function->node); - mutex_unlock(&pcs->mutex); -} - /** * pcs_get_pin_by_offset() - get a pin index based on the register offset * @pcs: pcs driver instance @@ -1103,7 +1036,7 @@ free_pingroups: pinctrl_generic_remove_last_group(pcs->pctl); *num_maps = 1; free_function: - pcs_remove_function(pcs, function); + pinmux_generic_remove_last_function(pcs->pctl); free_pins: devm_kfree(pcs->dev, pins); @@ -1235,8 +1168,7 @@ free_pingroups: pinctrl_generic_remove_last_group(pcs->pctl); *num_maps = 1; free_function: - pcs_remove_function(pcs, function); - + pinmux_generic_remove_last_function(pcs->pctl); free_pins: devm_kfree(pcs->dev, pins); @@ -1303,33 +1235,6 @@ free_map: return ret; } -/** - * pcs_free_funcs() - free memory used by functions - * @pcs: pcs driver instance - */ -static void pcs_free_funcs(struct pcs_device *pcs) -{ - struct list_head *pos, *tmp; - int i; - - mutex_lock(&pcs->mutex); - for (i = 0; i < pcs->nfuncs; i++) { - struct pcs_function *func; - - func = radix_tree_lookup(&pcs->ftree, i); - if (!func) - continue; - radix_tree_delete(&pcs->ftree, i); - } - list_for_each_safe(pos, tmp, &pcs->functions) { - struct pcs_function *function; - - function = list_entry(pos, struct pcs_function, node); - list_del(&function->node); - } - mutex_unlock(&pcs->mutex); -} - /** * pcs_irq_free() - free interrupt * @pcs: pcs driver instance @@ -1358,7 +1263,6 @@ static void pcs_free_resources(struct pcs_device *pcs) { pcs_irq_free(pcs); pinctrl_unregister(pcs->pctl); - pcs_free_funcs(pcs); #if IS_BUILTIN(CONFIG_PINCTRL_SINGLE) if (pcs->missing_nr_pinctrl_cells) @@ -1753,7 +1657,6 @@ static int pcs_probe(struct platform_device *pdev) pcs->np = np; raw_spin_lock_init(&pcs->lock); mutex_init(&pcs->mutex); - INIT_LIST_HEAD(&pcs->functions); INIT_LIST_HEAD(&pcs->gpiofuncs); soc = match->data; pcs->flags = soc->flags; @@ -1814,7 +1717,6 @@ static int pcs_probe(struct platform_device *pdev) return -ENODEV; } - INIT_RADIX_TREE(&pcs->ftree, GFP_KERNEL); platform_set_drvdata(pdev, pcs); switch (pcs->width) { From 824e4d954dfbf7ccb22340d4b56db64f9378d846 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 2 Jan 2017 09:42:28 +0100 Subject: [PATCH 0082/1587] pinctrl: qcom: msm8660: rename some SDC1->SDC4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These four pins are for SDC4, not SDC1. They are grouped for SDC4 later in the file so this must be a typo. Reviewed-by: Björn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-msm8660.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8660.c b/drivers/pinctrl/qcom/pinctrl-msm8660.c index 5591d093bf78..bb71dd1e6279 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8660.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8660.c @@ -193,9 +193,9 @@ static const struct pinctrl_pin_desc msm8660_pins[] = { PINCTRL_PIN(171, "GPIO_171"), PINCTRL_PIN(172, "GPIO_172"), - PINCTRL_PIN(173, "SDC1_CLK"), - PINCTRL_PIN(174, "SDC1_CMD"), - PINCTRL_PIN(175, "SDC1_DATA"), + PINCTRL_PIN(173, "SDC4_CLK"), + PINCTRL_PIN(174, "SDC4_CMD"), + PINCTRL_PIN(175, "SDC4_DATA"), PINCTRL_PIN(176, "SDC3_CLK"), PINCTRL_PIN(177, "SDC3_CMD"), PINCTRL_PIN(178, "SDC3_DATA"), From e566fc11ea76ec10a42fc92c5561ace4479770dd Mon Sep 17 00:00:00 2001 From: Gary Bisson Date: Mon, 2 Jan 2017 19:20:21 +0100 Subject: [PATCH 0083/1587] pinctrl: imx: use generic pinctrl helpers for managing groups Now using group_desc structure instead of imx_pin_group. Also leveraging generic functions to retrieve groups count/name/pins. The imx_free_pingroups function can be removed since it is now handled by the core driver during unregister. Finally the device tree parsing is moved after the pinctrl driver registration since this latter initializes the radix trees. Signed-off-by: Gary Bisson Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/Kconfig | 1 + drivers/pinctrl/freescale/pinctrl-imx.c | 190 +++++++++--------------- drivers/pinctrl/freescale/pinctrl-imx.h | 19 +-- 3 files changed, 69 insertions(+), 141 deletions(-) diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index fc8cbf611723..cb50e21615da 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -1,5 +1,6 @@ config PINCTRL_IMX bool + select GENERIC_PINCTRL_GROUPS select PINMUX select PINCONF select REGMAP diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index e832a2c7af68..62c20f661fed 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -45,15 +45,15 @@ struct imx_pinctrl { struct imx_pinctrl_soc_info *info; }; -static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name( - struct imx_pinctrl_soc_info *info, +static inline const struct group_desc *imx_pinctrl_find_group_by_name( + struct pinctrl_dev *pctldev, const char *name) { - const struct imx_pin_group *grp = NULL; + const struct group_desc *grp = NULL; int i; - for (i = 0; i < info->ngroups; i++) { - grp = radix_tree_lookup(&info->pgtree, i); + for (i = 0; i < pctldev->num_groups; i++) { + grp = pinctrl_generic_get_group(pctldev, i); if (grp && !strcmp(grp->name, name)) break; } @@ -61,49 +61,6 @@ static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name( return grp; } -static int imx_get_groups_count(struct pinctrl_dev *pctldev) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - - return info->ngroups; -} - -static const char *imx_get_group_name(struct pinctrl_dev *pctldev, - unsigned selector) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - struct imx_pin_group *grp = NULL; - - grp = radix_tree_lookup(&info->pgtree, selector); - if (!grp) - return NULL; - - return grp->name; -} - -static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, - const unsigned **pins, - unsigned *npins) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - struct imx_pin_group *grp = NULL; - - if (selector >= info->ngroups) - return -EINVAL; - - grp = radix_tree_lookup(&info->pgtree, selector); - if (!grp) - return -EINVAL; - - *pins = grp->pin_ids; - *npins = grp->npins; - - return 0; -} - static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset) { @@ -116,7 +73,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); struct imx_pinctrl_soc_info *info = ipctl->info; - const struct imx_pin_group *grp; + const struct group_desc *grp; struct pinctrl_map *new_map; struct device_node *parent; int map_num = 1; @@ -126,15 +83,17 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, * first find the group of this node and check if we need create * config maps for pins */ - grp = imx_pinctrl_find_group_by_name(info, np->name); + grp = imx_pinctrl_find_group_by_name(pctldev, np->name); if (!grp) { dev_err(info->dev, "unable to find group for node %s\n", np->name); return -EINVAL; } - for (i = 0; i < grp->npins; i++) { - if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) + for (i = 0; i < grp->num_pins; i++) { + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; + + if (!(pin->config & IMX_NO_PAD_CTL)) map_num++; } @@ -158,12 +117,14 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, /* create config map */ new_map++; - for (i = j = 0; i < grp->npins; i++) { - if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) { + for (i = j = 0; i < grp->num_pins; i++) { + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; + + if (!(pin->config & IMX_NO_PAD_CTL)) { new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; new_map[j].data.configs.group_or_pin = - pin_get_name(pctldev, grp->pins[i].pin); - new_map[j].data.configs.configs = &grp->pins[i].config; + pin_get_name(pctldev, pin->pin); + new_map[j].data.configs.configs = &pin->config; new_map[j].data.configs.num_configs = 1; j++; } @@ -182,9 +143,9 @@ static void imx_dt_free_map(struct pinctrl_dev *pctldev, } static const struct pinctrl_ops imx_pctrl_ops = { - .get_groups_count = imx_get_groups_count, - .get_group_name = imx_get_group_name, - .get_group_pins = imx_get_group_pins, + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, .pin_dbg_show = imx_pin_dbg_show, .dt_node_to_map = imx_dt_node_to_map, .dt_free_map = imx_dt_free_map, @@ -199,14 +160,14 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, const struct imx_pin_reg *pin_reg; unsigned int npins, pin_id; int i; - struct imx_pin_group *grp = NULL; + struct group_desc *grp = NULL; struct imx_pmx_func *func = NULL; /* * Configure the mux mode for each pin in the group for a specific * function. */ - grp = radix_tree_lookup(&info->pgtree, group); + grp = pinctrl_generic_get_group(pctldev, group); if (!grp) return -EINVAL; @@ -214,13 +175,14 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, if (!func) return -EINVAL; - npins = grp->npins; + npins = grp->num_pins; dev_dbg(ipctl->dev, "enable function %s group %s\n", func->name, grp->name); for (i = 0; i < npins; i++) { - struct imx_pin *pin = &grp->pins[i]; + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; + pin_id = pin->pin; pin_reg = &info->pin_regs[pin_id]; @@ -335,7 +297,7 @@ static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; - struct imx_pin_group *grp; + struct group_desc *grp; struct imx_pin *imx_pin; unsigned int pin, group; u32 reg; @@ -349,12 +311,12 @@ static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, return -EINVAL; /* Find the pinctrl config with GPIO mux mode for the requested pin */ - for (group = 0; group < info->ngroups; group++) { - grp = radix_tree_lookup(&info->pgtree, group); + for (group = 0; group < pctldev->num_groups; group++) { + grp = pinctrl_generic_get_group(pctldev, group); if (!grp) continue; - for (pin = 0; pin < grp->npins; pin++) { - imx_pin = &grp->pins[pin]; + for (pin = 0; pin < grp->num_pins; pin++) { + imx_pin = &((struct imx_pin *)(grp->data))[pin]; if (imx_pin->pin == offset && !imx_pin->mux_mode) goto mux_pin; } @@ -512,23 +474,22 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned group) { - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - struct imx_pin_group *grp; + struct group_desc *grp; unsigned long config; const char *name; int i, ret; - if (group > info->ngroups) + if (group > pctldev->num_groups) return; seq_printf(s, "\n"); - grp = radix_tree_lookup(&info->pgtree, group); + grp = pinctrl_generic_get_group(pctldev, group); if (!grp) return; - for (i = 0; i < grp->npins; i++) { - struct imx_pin *pin = &grp->pins[i]; + for (i = 0; i < grp->num_pins; i++) { + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; + name = pin_get_name(pctldev, pin->pin); ret = imx_pinconf_get(pctldev, pin->pin, &config); if (ret) @@ -552,7 +513,7 @@ static const struct pinconf_ops imx_pinconf_ops = { #define SHARE_FSL_PIN_SIZE 20 static int imx_pinctrl_parse_groups(struct device_node *np, - struct imx_pin_group *grp, + struct group_desc *grp, struct imx_pinctrl_soc_info *info, u32 index) { @@ -586,20 +547,20 @@ static int imx_pinctrl_parse_groups(struct device_node *np, return -EINVAL; } - grp->npins = size / pin_size; - grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(struct imx_pin), - GFP_KERNEL); - grp->pin_ids = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), - GFP_KERNEL); - if (!grp->pins || ! grp->pin_ids) + grp->num_pins = size / pin_size; + grp->data = devm_kzalloc(info->dev, grp->num_pins * + sizeof(struct imx_pin), GFP_KERNEL); + grp->pins = devm_kzalloc(info->dev, grp->num_pins * + sizeof(unsigned int), GFP_KERNEL); + if (!grp->pins || !grp->data) return -ENOMEM; - for (i = 0; i < grp->npins; i++) { + for (i = 0; i < grp->num_pins; i++) { u32 mux_reg = be32_to_cpu(*list++); u32 conf_reg; unsigned int pin_id; struct imx_pin_reg *pin_reg; - struct imx_pin *pin = &grp->pins[i]; + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg) mux_reg = -1; @@ -615,7 +576,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np, pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4; pin_reg = &info->pin_regs[pin_id]; pin->pin = pin_id; - grp->pin_ids[i] = pin_id; + grp->pins[i] = pin_id; pin_reg->mux_reg = mux_reg; pin_reg->conf_reg = conf_reg; pin->input_reg = be32_to_cpu(*list++); @@ -636,12 +597,14 @@ static int imx_pinctrl_parse_groups(struct device_node *np, } static int imx_pinctrl_parse_functions(struct device_node *np, - struct imx_pinctrl_soc_info *info, + struct imx_pinctrl *ipctl, u32 index) { + struct pinctrl_dev *pctl = ipctl->pctl; + struct imx_pinctrl_soc_info *info = ipctl->info; struct device_node *child; struct imx_pmx_func *func; - struct imx_pin_group *grp; + struct group_desc *grp; u32 i = 0; dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); @@ -663,13 +626,14 @@ static int imx_pinctrl_parse_functions(struct device_node *np, for_each_child_of_node(np, child) { func->groups[i] = child->name; - grp = devm_kzalloc(info->dev, sizeof(struct imx_pin_group), + grp = devm_kzalloc(info->dev, sizeof(struct group_desc), GFP_KERNEL); if (!grp) return -ENOMEM; mutex_lock(&info->mutex); - radix_tree_insert(&info->pgtree, info->group_index++, grp); + radix_tree_insert(&pctl->pin_group_tree, + info->group_index++, grp); mutex_unlock(&info->mutex); imx_pinctrl_parse_groups(child, grp, info, i++); @@ -702,10 +666,12 @@ static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np) } static int imx_pinctrl_probe_dt(struct platform_device *pdev, - struct imx_pinctrl_soc_info *info) + struct imx_pinctrl *ipctl) { struct device_node *np = pdev->dev.of_node; struct device_node *child; + struct pinctrl_dev *pctl = ipctl->pctl; + struct imx_pinctrl_soc_info *info = ipctl->info; u32 nfuncs = 0; u32 i = 0; bool flat_funcs; @@ -740,19 +706,19 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, info->group_index = 0; if (flat_funcs) { - info->ngroups = of_get_child_count(np); + pctl->num_groups = of_get_child_count(np); } else { - info->ngroups = 0; + pctl->num_groups = 0; for_each_child_of_node(np, child) - info->ngroups += of_get_child_count(child); + pctl->num_groups += of_get_child_count(child); } if (flat_funcs) { - imx_pinctrl_parse_functions(np, info, 0); + imx_pinctrl_parse_functions(np, ipctl, 0); } else { i = 0; for_each_child_of_node(np, child) - imx_pinctrl_parse_functions(child, info, i++); + imx_pinctrl_parse_functions(child, ipctl, i++); } return 0; @@ -778,26 +744,6 @@ static void imx_free_funcs(struct imx_pinctrl_soc_info *info) mutex_unlock(&info->mutex); } -/* - * imx_free_pingroups() - free memory used by pingroups - * @info: info driver instance - */ -static void imx_free_pingroups(struct imx_pinctrl_soc_info *info) -{ - int i; - - mutex_lock(&info->mutex); - for (i = 0; i < info->ngroups; i++) { - struct imx_pin_group *pingroup; - - pingroup = radix_tree_lookup(&info->pgtree, i); - if (!pingroup) - continue; - radix_tree_delete(&info->pgtree, i); - } - mutex_unlock(&info->mutex); -} - /* * imx_free_resources() - free memory used by this driver * @info: info driver instance @@ -808,7 +754,6 @@ static void imx_free_resources(struct imx_pinctrl *ipctl) pinctrl_unregister(ipctl->pctl); imx_free_funcs(ipctl->info); - imx_free_pingroups(ipctl->info); } int imx_pinctrl_probe(struct platform_device *pdev, @@ -886,15 +831,8 @@ int imx_pinctrl_probe(struct platform_device *pdev, mutex_init(&info->mutex); - INIT_RADIX_TREE(&info->pgtree, GFP_KERNEL); INIT_RADIX_TREE(&info->ftree, GFP_KERNEL); - ret = imx_pinctrl_probe_dt(pdev, info); - if (ret) { - dev_err(&pdev->dev, "fail to probe dt properties\n"); - goto free; - } - ipctl->info = info; ipctl->dev = info->dev; platform_set_drvdata(pdev, ipctl); @@ -906,6 +844,12 @@ int imx_pinctrl_probe(struct platform_device *pdev, goto free; } + ret = imx_pinctrl_probe_dt(pdev, ipctl); + if (ret) { + dev_err(&pdev->dev, "fail to probe dt properties\n"); + goto free; + } + dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); return 0; diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index 62aa8f8f57e9..3c51db15223b 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -18,7 +18,7 @@ struct platform_device; /** - * struct imx_pin_group - describes a single i.MX pin + * struct imx_pin - describes a single i.MX pin * @pin: the pin_id of this pin * @mux_mode: the mux mode for this pin. * @input_reg: the select input register offset for this pin if any @@ -34,21 +34,6 @@ struct imx_pin { unsigned long config; }; -/** - * struct imx_pin_group - describes an IMX pin group - * @name: the name of this specific pin group - * @npins: the number of pins in this group array, i.e. the number of - * elements in .pins so we can iterate over that array - * @pin_ids: array of pin_ids. pinctrl forces us to maintain such an array - * @pins: array of pins - */ -struct imx_pin_group { - const char *name; - unsigned npins; - unsigned int *pin_ids; - struct imx_pin *pins; -}; - /** * struct imx_pmx_func - describes IMX pinmux functions * @name: the name of this specific function @@ -76,13 +61,11 @@ struct imx_pinctrl_soc_info { const struct pinctrl_pin_desc *pins; unsigned int npins; struct imx_pin_reg *pin_regs; - unsigned int ngroups; unsigned int group_index; unsigned int nfunctions; unsigned int flags; const char *gpr_compatible; struct radix_tree_root ftree; - struct radix_tree_root pgtree; struct mutex mutex; }; From 3fd6d6ad73af90522321451a2d10b0a8967d47d1 Mon Sep 17 00:00:00 2001 From: Gary Bisson Date: Mon, 2 Jan 2017 19:20:22 +0100 Subject: [PATCH 0084/1587] pinctrl: imx: use generic pinmux helpers for managing functions Now using function_desc structure instead of imx_pmx_func. Also leveraging generic functions to retrieve functions count/name/groups. The imx_free_funcs function can be removed since it is now handled by the core driver during unregister. Signed-off-by: Gary Bisson Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/Kconfig | 2 +- drivers/pinctrl/freescale/pinctrl-imx.c | 96 +++++-------------------- drivers/pinctrl/freescale/pinctrl-imx.h | 14 ---- 3 files changed, 18 insertions(+), 94 deletions(-) diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index cb50e21615da..cae05e76c111 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -1,7 +1,7 @@ config PINCTRL_IMX bool select GENERIC_PINCTRL_GROUPS - select PINMUX + select GENERIC_PINMUX_FUNCTIONS select PINCONF select REGMAP diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 62c20f661fed..bccd9416d44f 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -27,6 +27,7 @@ #include #include "../core.h" +#include "../pinmux.h" #include "pinctrl-imx.h" /* The bits in CONFIG cell defined in binding doc*/ @@ -161,7 +162,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, unsigned int npins, pin_id; int i; struct group_desc *grp = NULL; - struct imx_pmx_func *func = NULL; + struct function_desc *func = NULL; /* * Configure the mux mode for each pin in the group for a specific @@ -171,7 +172,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, if (!grp) return -EINVAL; - func = radix_tree_lookup(&info->ftree, selector); + func = pinmux_generic_get_function(pctldev, selector); if (!func) return -EINVAL; @@ -251,46 +252,6 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -static int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - - return info->nfunctions; -} - -static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev, - unsigned selector) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - struct imx_pmx_func *func = NULL; - - func = radix_tree_lookup(&info->ftree, selector); - if (!func) - return NULL; - - return func->name; -} - -static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, - const char * const **groups, - unsigned * const num_groups) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - struct imx_pmx_func *func = NULL; - - func = radix_tree_lookup(&info->ftree, selector); - if (!func) - return -EINVAL; - - *groups = func->groups; - *num_groups = func->num_groups; - - return 0; -} - static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset) { @@ -389,9 +350,9 @@ static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, } static const struct pinmux_ops imx_pmx_ops = { - .get_functions_count = imx_pmx_get_funcs_count, - .get_function_name = imx_pmx_get_func_name, - .get_function_groups = imx_pmx_get_groups, + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, .set_mux = imx_pmx_set, .gpio_request_enable = imx_pmx_gpio_request_enable, .gpio_disable_free = imx_pmx_gpio_disable_free, @@ -603,28 +564,29 @@ static int imx_pinctrl_parse_functions(struct device_node *np, struct pinctrl_dev *pctl = ipctl->pctl; struct imx_pinctrl_soc_info *info = ipctl->info; struct device_node *child; - struct imx_pmx_func *func; + struct function_desc *func; struct group_desc *grp; u32 i = 0; dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); - func = radix_tree_lookup(&info->ftree, index); + func = pinmux_generic_get_function(pctl, index); if (!func) return -EINVAL; /* Initialise function */ func->name = np->name; - func->num_groups = of_get_child_count(np); - if (func->num_groups == 0) { + func->num_group_names = of_get_child_count(np); + if (func->num_group_names == 0) { dev_err(info->dev, "no groups defined in %s\n", np->full_name); return -EINVAL; } - func->groups = devm_kzalloc(info->dev, - func->num_groups * sizeof(char *), GFP_KERNEL); + func->group_names = devm_kzalloc(info->dev, + func->num_group_names * + sizeof(char *), GFP_KERNEL); for_each_child_of_node(np, child) { - func->groups[i] = child->name; + func->group_names[i] = child->name; grp = devm_kzalloc(info->dev, sizeof(struct group_desc), GFP_KERNEL); @@ -691,7 +653,7 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, } for (i = 0; i < nfuncs; i++) { - struct imx_pmx_func *function; + struct function_desc *function; function = devm_kzalloc(&pdev->dev, sizeof(*function), GFP_KERNEL); @@ -699,10 +661,10 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, return -ENOMEM; mutex_lock(&info->mutex); - radix_tree_insert(&info->ftree, i, function); + radix_tree_insert(&pctl->pin_function_tree, i, function); mutex_unlock(&info->mutex); } - info->nfunctions = nfuncs; + pctl->num_functions = nfuncs; info->group_index = 0; if (flat_funcs) { @@ -724,26 +686,6 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, return 0; } -/* - * imx_free_funcs() - free memory used by functions - * @info: info driver instance - */ -static void imx_free_funcs(struct imx_pinctrl_soc_info *info) -{ - int i; - - mutex_lock(&info->mutex); - for (i = 0; i < info->nfunctions; i++) { - struct imx_pmx_func *func; - - func = radix_tree_lookup(&info->ftree, i); - if (!func) - continue; - radix_tree_delete(&info->ftree, i); - } - mutex_unlock(&info->mutex); -} - /* * imx_free_resources() - free memory used by this driver * @info: info driver instance @@ -752,8 +694,6 @@ static void imx_free_resources(struct imx_pinctrl *ipctl) { if (ipctl->pctl) pinctrl_unregister(ipctl->pctl); - - imx_free_funcs(ipctl->info); } int imx_pinctrl_probe(struct platform_device *pdev, @@ -831,8 +771,6 @@ int imx_pinctrl_probe(struct platform_device *pdev, mutex_init(&info->mutex); - INIT_RADIX_TREE(&info->ftree, GFP_KERNEL); - ipctl->info = info; ipctl->dev = info->dev; platform_set_drvdata(pdev, ipctl); diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index 3c51db15223b..ff2d3e56b7c5 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -34,18 +34,6 @@ struct imx_pin { unsigned long config; }; -/** - * struct imx_pmx_func - describes IMX pinmux functions - * @name: the name of this specific function - * @groups: corresponding pin groups - * @num_groups: the number of groups - */ -struct imx_pmx_func { - const char *name; - const char **groups; - unsigned num_groups; -}; - /** * struct imx_pin_reg - describe a pin reg map * @mux_reg: mux register offset @@ -62,10 +50,8 @@ struct imx_pinctrl_soc_info { unsigned int npins; struct imx_pin_reg *pin_regs; unsigned int group_index; - unsigned int nfunctions; unsigned int flags; const char *gpr_compatible; - struct radix_tree_root ftree; struct mutex mutex; }; From 6ac4c1ad2eda7f0e8475c85b2647b4b6eabfcc7b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 3 Jan 2017 09:18:58 +0100 Subject: [PATCH 0085/1587] pinctrl: amd: fix compilation warning 3bfd44306c65 ("pinctrl: amd: Add support for additional GPIO") created the following warning: drivers/pinctrl/pinctrl-amd.c: In function 'amd_gpio_dbg_show': drivers/pinctrl/pinctrl-amd.c:210:3: warning: 'pin_num' may be used uninitialized in this function [-Wmaybe-uninitialized] for (; i < pin_num; i++) { ^ drivers/pinctrl/pinctrl-amd.c:172:21: warning: 'i' may be used uninitialized in this function [-Wmaybe-uninitialized] unsigned int bank, i, pin_num; ^ Fix this by adding a guarding default case for illegal bank numbers. Cc: S-k Shyam-sundar Cc: Nehal Shah Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-amd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 47b17100410e..c2203699f1ab 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -206,6 +206,9 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) i = 192; pin_num = AMD_GPIO_PINS_BANK3 + i; break; + default: + /* Illegal bank number, ignore */ + continue; } for (; i < pin_num; i++) { seq_printf(s, "pin%d\t", i); From 88b50ce3ab5af60c85905784c938a35c967addf4 Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Mon, 2 Jan 2017 19:20:55 -0800 Subject: [PATCH 0086/1587] fs: udf: Replace CURRENT_TIME with current_time() CURRENT_TIME is not y2038 safe. CURRENT_TIME macro is also not appropriate for filesystems as it doesn't use the right granularity for filesystem timestamps. Logical Volume Integrity format is described to have the same timestamp format for "Recording Date and time" as the other [a,c,m]timestamps. The function udf_time_to_disk_format() does this conversion. Hence the timestamp is passed directly to the function and not truncated. This is as per Arnd's suggestion on the thread. This is also in preparation for the patch that transitions vfs timestamps to use 64 bit time and hence make them y2038 safe. As part of the effort current_time() will be extended to do range checks. Signed-off-by: Deepa Dinamani Reviewed-by: Jan Kara Reviewed-by: Arnd Bergmann Signed-off-by: Jan Kara --- fs/udf/super.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 4942549e7dc8..967ad8775af2 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1986,6 +1986,7 @@ static void udf_open_lvid(struct super_block *sb) struct buffer_head *bh = sbi->s_lvid_bh; struct logicalVolIntegrityDesc *lvid; struct logicalVolIntegrityDescImpUse *lvidiu; + struct timespec ts; if (!bh) return; @@ -1997,8 +1998,8 @@ static void udf_open_lvid(struct super_block *sb) mutex_lock(&sbi->s_alloc_mutex); lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - udf_time_to_disk_stamp(&lvid->recordingDateAndTime, - CURRENT_TIME); + ktime_get_real_ts(&ts); + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts); lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN); lvid->descTag.descCRC = cpu_to_le16( @@ -2019,6 +2020,7 @@ static void udf_close_lvid(struct super_block *sb) struct buffer_head *bh = sbi->s_lvid_bh; struct logicalVolIntegrityDesc *lvid; struct logicalVolIntegrityDescImpUse *lvidiu; + struct timespec ts; if (!bh) return; @@ -2030,7 +2032,8 @@ static void udf_close_lvid(struct super_block *sb) mutex_lock(&sbi->s_alloc_mutex); lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME); + ktime_get_real_ts(&ts); + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts); if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) From a17f0cb5b9eaf8212b396d2381cf7594cd5315c7 Mon Sep 17 00:00:00 2001 From: Steve Kenton Date: Mon, 2 Jan 2017 13:25:34 -0500 Subject: [PATCH 0087/1587] fs/udf: make #ifdef UDF_PREALLOCATE unconditional Signed-off-by: Steve Kenton Signed-off-by: Jan Kara --- fs/udf/inode.c | 2 -- fs/udf/udfdecl.h | 1 - 2 files changed, 3 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 0f3db71753aa..3a5ac2221a88 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -857,14 +857,12 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, * block */ udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum); -#ifdef UDF_PREALLOCATE /* We preallocate blocks only for regular files. It also makes sense * for directories but there's a problem when to drop the * preallocation. We might use some delayed work for that but I feel * it's overengineering for a filesystem like UDF. */ if (S_ISREG(inode->i_mode)) udf_prealloc_extents(inode, c, lastblock, laarr, &endnum); -#endif /* merge any continuous blocks in laarr */ udf_merge_extents(inode, laarr, &endnum); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 263829ef1873..b608624e7089 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -15,7 +15,6 @@ #include "udfend.h" #include "udf_i.h" -#define UDF_PREALLOCATE #define UDF_DEFAULT_PREALLOC_BLOCKS 8 extern __printf(3, 4) void _udf_err(struct super_block *sb, From ccebb88aea1329221e1063906f4846b532a57fb5 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 31 Oct 2016 15:19:55 +0100 Subject: [PATCH 0088/1587] MIPS: zboot: Add "uzImage.bin" target uzImage.bin is vmlinuz.bin wrapped in a legacy U-Boot image. Since the extraction code is inside the image, it does not depend on the boot loader to extract the kernel. Signed-off-by: Maarten ter Huurne Cc: Alban Bedel Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14473/ Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 4 ++++ arch/mips/boot/compressed/Makefile | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 1a6bac7b076f..0f6e95cba43c 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -320,6 +320,9 @@ bootz-y := vmlinuz bootz-y += vmlinuz.bin bootz-y += vmlinuz.ecoff bootz-y += vmlinuz.srec +ifeq ($(shell expr $(zload-y) \< 0xffffffff80000000 2> /dev/null), 0) +bootz-y += uzImage.bin +endif ifdef CONFIG_LASAT rom.bin rom.sw: vmlinux @@ -433,6 +436,7 @@ define archhelp echo ' uImage.gz - U-Boot image (gzip)' echo ' uImage.lzma - U-Boot image (lzma)' echo ' uImage.lzo - U-Boot image (lzo)' + echo ' uzImage.bin - U-Boot image (self-extracting)' echo ' dtbs - Device-tree blobs for enabled boards' echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)' echo diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 90aca95fe314..011b14512c05 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -84,6 +84,7 @@ else VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \ $(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS)) endif +UIMAGE_LOADADDR = $(VMLINUZ_LOAD_ADDRESS) vmlinuzobjs-y += $(obj)/piggy.o @@ -129,4 +130,7 @@ OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec vmlinuz.srec: vmlinuz $(call cmd,objcopy) +uzImage.bin: vmlinuz.bin FORCE + $(call if_changed,uimage,none) + clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} From 3c2b02397893c40ce46e2297ba980fbc40d908b0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 29 Oct 2016 21:36:59 +0200 Subject: [PATCH 0089/1587] MIPS: TXx9: 7segled: use permission-specific DEVICE_ATTR variants Use DEVICE_ATTR_WO for write only attributes. This simplifies the source code, improves readbility, and reduces the chance of inconsistencies. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @wo@ declarer name DEVICE_ATTR; identifier x,x_store; @@ DEVICE_ATTR(x, \(0200\|S_IWUSR\), NULL, x_store); @script:ocaml@ x << wo.x; x_store << wo.x_store; @@ if not (x^"_store" = x_store) then Coccilib.include_match false @@ declarer name DEVICE_ATTR_WO; identifier wo.x,wo.x_store; @@ - DEVICE_ATTR(x, \(0200\|S_IWUSR\), NULL, x_store); + DEVICE_ATTR_WO(x); // Signed-off-by: Julia Lawall Cc: kernel-janitors@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14463/ Signed-off-by: Ralf Baechle --- arch/mips/txx9/generic/7segled.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/txx9/generic/7segled.c b/arch/mips/txx9/generic/7segled.c index 566c58bd44d0..2203c2548cb4 100644 --- a/arch/mips/txx9/generic/7segled.c +++ b/arch/mips/txx9/generic/7segled.c @@ -55,8 +55,8 @@ static ssize_t raw_store(struct device *dev, return size; } -static DEVICE_ATTR(ascii, 0200, NULL, ascii_store); -static DEVICE_ATTR(raw, 0200, NULL, raw_store); +static DEVICE_ATTR_WO(ascii); +static DEVICE_ATTR_WO(raw); static ssize_t map_seg7_show(struct device *dev, struct device_attribute *attr, From 2b58a76e2fd6c8064c5049c4dda1f4c329a33478 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 27 Nov 2016 02:30:51 +0200 Subject: [PATCH 0090/1587] MIPS: Octeon: Kill cvmx_helper_link_autoconf() Kill cvmx_helper_link_autoconf(). Nobody uses this function. Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14626/ Signed-off-by: Ralf Baechle --- .../executive/cvmx-helper-rgmii.c | 3 +- .../executive/cvmx-helper-sgmii.c | 3 +- .../cavium-octeon/executive/cvmx-helper-spi.c | 3 +- .../executive/cvmx-helper-xaui.c | 3 +- .../cavium-octeon/executive/cvmx-helper.c | 47 +------------------ .../include/asm/octeon/cvmx-helper-rgmii.h | 3 +- .../include/asm/octeon/cvmx-helper-sgmii.h | 3 +- .../mips/include/asm/octeon/cvmx-helper-spi.h | 3 +- .../include/asm/octeon/cvmx-helper-xaui.h | 3 +- arch/mips/include/asm/octeon/cvmx-helper.h | 14 +----- 10 files changed, 10 insertions(+), 75 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c index 671ab1db2727..ba4753c23b03 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c @@ -287,8 +287,7 @@ cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port) * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c index 54375340afe8..578283350776 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c @@ -500,8 +500,7 @@ cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port) * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c b/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c index 1f3030c72d88..ef16aa00167b 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c @@ -188,8 +188,7 @@ cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port) * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c index d347fe13b666..19d54e02c185 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c @@ -295,8 +295,7 @@ cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port) * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index 6456af642471..f24be0b5db50 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -69,10 +69,6 @@ void (*cvmx_override_ipd_port_setup) (int ipd_port); /* Port count per interface */ static int interface_port_count[5]; -/* Port last configured link info index by IPD/PKO port */ -static cvmx_helper_link_info_t - port_link_info[CVMX_PIP_NUM_INPUT_PORTS]; - /** * Return the number of interfaces the chip has. Each interface * may have multiple ports. Most chips support two interfaces, @@ -1135,41 +1131,6 @@ int cvmx_helper_initialize_packet_io_local(void) return cvmx_pko_initialize_local(); } -/** - * Auto configure an IPD/PKO port link state and speed. This - * function basically does the equivalent of: - * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port)); - * - * @ipd_port: IPD/PKO port to auto configure - * - * Returns Link state after configure - */ -cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port) -{ - cvmx_helper_link_info_t link_info; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - - if (index >= cvmx_helper_ports_on_interface(interface)) { - link_info.u64 = 0; - return link_info; - } - - link_info = cvmx_helper_link_get(ipd_port); - if (link_info.u64 == port_link_info[ipd_port].u64) - return link_info; - - /* If we fail to set the link speed, port_link_info will not change */ - cvmx_helper_link_set(ipd_port, link_info); - - /* - * port_link_info should be the current value, which will be - * different than expect if cvmx_helper_link_set() failed. - */ - return port_link_info[ipd_port]; -} -EXPORT_SYMBOL_GPL(cvmx_helper_link_autoconf); - /** * Return the link state of an IPD/PKO port as returned by * auto negotiation. The result of this function may not match @@ -1233,8 +1194,7 @@ EXPORT_SYMBOL_GPL(cvmx_helper_link_get); * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state @@ -1276,11 +1236,6 @@ int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info) case CVMX_HELPER_INTERFACE_MODE_LOOP: break; } - /* Set the port_link_info here so that the link status is updated - no matter how cvmx_helper_link_set is called. We don't change - the value if link_set failed */ - if (result == 0) - port_link_info[ipd_port].u64 = link_info.u64; return result; } EXPORT_SYMBOL_GPL(cvmx_helper_link_set); diff --git a/arch/mips/include/asm/octeon/cvmx-helper-rgmii.h b/arch/mips/include/asm/octeon/cvmx-helper-rgmii.h index 4d7a3db3a9f6..f89775be7654 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper-rgmii.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-rgmii.h @@ -80,8 +80,7 @@ extern cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port); * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state diff --git a/arch/mips/include/asm/octeon/cvmx-helper-sgmii.h b/arch/mips/include/asm/octeon/cvmx-helper-sgmii.h index 4debb1c5153d..63fd21335e4b 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper-sgmii.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-sgmii.h @@ -74,8 +74,7 @@ extern cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port); * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state diff --git a/arch/mips/include/asm/octeon/cvmx-helper-spi.h b/arch/mips/include/asm/octeon/cvmx-helper-spi.h index 9f1c6b968f91..d5adf8592773 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper-spi.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-spi.h @@ -71,8 +71,7 @@ extern cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port); * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state diff --git a/arch/mips/include/asm/octeon/cvmx-helper-xaui.h b/arch/mips/include/asm/octeon/cvmx-helper-xaui.h index 5e89ed703eaa..f8ce53f6f28f 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper-xaui.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-xaui.h @@ -74,8 +74,7 @@ extern cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port); * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state diff --git a/arch/mips/include/asm/octeon/cvmx-helper.h b/arch/mips/include/asm/octeon/cvmx-helper.h index 5a3090dc6f2f..0ed87cb67e7f 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper.h +++ b/arch/mips/include/asm/octeon/cvmx-helper.h @@ -155,17 +155,6 @@ extern int cvmx_helper_get_number_of_interfaces(void); extern cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface); -/** - * Auto configure an IPD/PKO port link state and speed. This - * function basically does the equivalent of: - * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port)); - * - * @ipd_port: IPD/PKO port to auto configure - * - * Returns Link state after configure - */ -extern cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port); - /** * Return the link state of an IPD/PKO port as returned by * auto negotiation. The result of this function may not match @@ -182,8 +171,7 @@ extern cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port); * Configure an IPD/PKO port for the specified link state. This * function does not influence auto negotiation at the PHY level. * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. + * by cvmx_helper_link_get(). * * @ipd_port: IPD/PKO port to configure * @link_info: The new link state From 2cec11d871814cd65702ccd3591232ee9f185360 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 7 Dec 2016 10:05:15 +0100 Subject: [PATCH 0091/1587] MIPS: TXx9: Modernize printing of kernel messages - Convert from printk() to pr_*(), - Add missing continuations, to fix user-visible breakage, - Drop superfluous casts (u64 has been unsigned long long on all architectures for many years). On rbtx4927, this restores the kernel output like: -TX4927 SDRAMC -- - CR0:0000007e00000544 - TR:32800030e +TX4927 SDRAMC -- CR0:0000007e00000544 TR:32800030e and: -PCIC -- PCICLK: -Internal(33.3MHz) - +PCIC -- PCICLK:Internal(33.3MHz) Fixes: 4bcc595ccd80decb ("printk: reinstate KERN_CONT for printing continuation lines") Signed-off-by: Geert Uytterhoeven Reviewed-by: Atsushi Nemoto Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14646/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-tx4927.c | 22 +++++++++--------- arch/mips/pci/pci-tx4938.c | 30 ++++++++++++------------- arch/mips/pci/pci-tx4939.c | 10 ++++----- arch/mips/txx9/generic/pci.c | 28 +++++++++++------------ arch/mips/txx9/generic/setup_tx3927.c | 6 ++--- arch/mips/txx9/generic/setup_tx4927.c | 20 ++++++++--------- arch/mips/txx9/generic/setup_tx4938.c | 26 ++++++++++----------- arch/mips/txx9/generic/setup_tx4939.c | 8 +++---- arch/mips/txx9/generic/smsc_fdc37m81x.c | 17 ++++++-------- arch/mips/txx9/jmr3927/prom.c | 2 +- arch/mips/txx9/jmr3927/setup.c | 11 +++++---- arch/mips/txx9/rbtx4938/setup.c | 14 ++++++------ 12 files changed, 92 insertions(+), 102 deletions(-) diff --git a/arch/mips/pci/pci-tx4927.c b/arch/mips/pci/pci-tx4927.c index a032ae0a533d..9b3301d19a63 100644 --- a/arch/mips/pci/pci-tx4927.c +++ b/arch/mips/pci/pci-tx4927.c @@ -21,9 +21,9 @@ int __init tx4927_report_pciclk(void) { int pciclk = 0; - printk(KERN_INFO "PCIC --%s PCICLK:", - (__raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCI66) ? - " PCI66" : ""); + pr_info("PCIC --%s PCICLK:", + (__raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCI66) ? + " PCI66" : ""); if (__raw_readq(&tx4927_ccfgptr->pcfg) & TX4927_PCFG_PCICLKEN_ALL) { u64 ccfg = __raw_readq(&tx4927_ccfgptr->ccfg); switch ((unsigned long)ccfg & @@ -37,14 +37,14 @@ int __init tx4927_report_pciclk(void) case TX4927_CCFG_PCIDIVMODE_6: pciclk = txx9_cpu_clock / 6; break; } - printk("Internal(%u.%uMHz)", - (pciclk + 50000) / 1000000, - ((pciclk + 50000) / 100000) % 10); + pr_cont("Internal(%u.%uMHz)", + (pciclk + 50000) / 1000000, + ((pciclk + 50000) / 100000) % 10); } else { - printk("External"); + pr_cont("External"); pciclk = -1; } - printk("\n"); + pr_cont("\n"); return pciclk; } @@ -74,8 +74,8 @@ int __init tx4927_pciclk66_setup(void) } tx4927_ccfg_change(TX4927_CCFG_PCIDIVMODE_MASK, pcidivmode); - printk(KERN_DEBUG "PCICLK: ccfg:%08lx\n", - (unsigned long)__raw_readq(&tx4927_ccfgptr->ccfg)); + pr_debug("PCICLK: ccfg:%08lx\n", + (unsigned long)__raw_readq(&tx4927_ccfgptr->ccfg)); } else pciclk = -1; return pciclk; @@ -87,5 +87,5 @@ void __init tx4927_setup_pcierr_irq(void) tx4927_pcierr_interrupt, 0, "PCI error", (void *)TX4927_PCIC_REG)) - printk(KERN_WARNING "Failed to request irq for PCIERR\n"); + pr_warn("Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-tx4938.c b/arch/mips/pci/pci-tx4938.c index 141bba562488..000c0e1f9ef8 100644 --- a/arch/mips/pci/pci-tx4938.c +++ b/arch/mips/pci/pci-tx4938.c @@ -21,9 +21,9 @@ int __init tx4938_report_pciclk(void) { int pciclk = 0; - printk(KERN_INFO "PCIC --%s PCICLK:", - (__raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCI66) ? - " PCI66" : ""); + pr_info("PCIC --%s PCICLK:", + (__raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCI66) ? + " PCI66" : ""); if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_PCICLKEN_ALL) { u64 ccfg = __raw_readq(&tx4938_ccfgptr->ccfg); switch ((unsigned long)ccfg & @@ -45,14 +45,14 @@ int __init tx4938_report_pciclk(void) case TX4938_CCFG_PCIDIVMODE_11: pciclk = txx9_cpu_clock / 11; break; } - printk("Internal(%u.%uMHz)", - (pciclk + 50000) / 1000000, - ((pciclk + 50000) / 100000) % 10); + pr_cont("Internal(%u.%uMHz)", + (pciclk + 50000) / 1000000, + ((pciclk + 50000) / 100000) % 10); } else { - printk("External"); + pr_cont("External"); pciclk = -1; } - printk("\n"); + pr_cont("\n"); return pciclk; } @@ -62,10 +62,10 @@ void __init tx4938_report_pci1clk(void) unsigned int pciclk = txx9_gbus_clock / ((ccfg & TX4938_CCFG_PCI1DMD) ? 4 : 2); - printk(KERN_INFO "PCIC1 -- %sPCICLK:%u.%uMHz\n", - (ccfg & TX4938_CCFG_PCI1_66) ? "PCI66 " : "", - (pciclk + 50000) / 1000000, - ((pciclk + 50000) / 100000) % 10); + pr_info("PCIC1 -- %sPCICLK:%u.%uMHz\n", + (ccfg & TX4938_CCFG_PCI1_66) ? "PCI66 " : "", + (pciclk + 50000) / 1000000, + ((pciclk + 50000) / 100000) % 10); } int __init tx4938_pciclk66_setup(void) @@ -105,8 +105,8 @@ int __init tx4938_pciclk66_setup(void) } tx4938_ccfg_change(TX4938_CCFG_PCIDIVMODE_MASK, pcidivmode); - printk(KERN_DEBUG "PCICLK: ccfg:%08lx\n", - (unsigned long)__raw_readq(&tx4938_ccfgptr->ccfg)); + pr_debug("PCICLK: ccfg:%08lx\n", + (unsigned long)__raw_readq(&tx4938_ccfgptr->ccfg)); } else pciclk = -1; return pciclk; @@ -138,5 +138,5 @@ void __init tx4938_setup_pcierr_irq(void) tx4927_pcierr_interrupt, 0, "PCI error", (void *)TX4927_PCIC_REG)) - printk(KERN_WARNING "Failed to request irq for PCIERR\n"); + pr_warn("Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-tx4939.c b/arch/mips/pci/pci-tx4939.c index cd8ed09c4f53..9d6acc00f348 100644 --- a/arch/mips/pci/pci-tx4939.c +++ b/arch/mips/pci/pci-tx4939.c @@ -28,14 +28,14 @@ int __init tx4939_report_pciclk(void) pciclk = txx9_master_clock * 20 / 6; if (!(__raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_PCI66)) pciclk /= 2; - printk(KERN_CONT "Internal(%u.%uMHz)", - (pciclk + 50000) / 1000000, - ((pciclk + 50000) / 100000) % 10); + pr_cont("Internal(%u.%uMHz)", + (pciclk + 50000) / 1000000, + ((pciclk + 50000) / 100000) % 10); } else { - printk(KERN_CONT "External"); + pr_cont("External"); pciclk = -1; } - printk(KERN_CONT "\n"); + pr_cont("\n"); return pciclk; } diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 285d84e5c7b9..0bd2a1e1ff9a 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c @@ -55,7 +55,7 @@ int __init txx9_pci66_check(struct pci_controller *hose, int top_bus, /* It seems SLC90E66 needs some time after PCI reset... */ mdelay(80); - printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n"); + pr_info("PCI: Checking 66MHz capabilities...\n"); for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { if (PCI_FUNC(pci_devfn)) @@ -74,9 +74,8 @@ int __init txx9_pci66_check(struct pci_controller *hose, int top_bus, early_read_config_word(hose, top_bus, current_bus, pci_devfn, PCI_STATUS, &stat); if (!(stat & PCI_STATUS_66MHZ)) { - printk(KERN_DEBUG - "PCI: %02x:%02x not 66MHz capable.\n", - current_bus, pci_devfn); + pr_debug("PCI: %02x:%02x not 66MHz capable.\n", + current_bus, pci_devfn); cap66 = 0; break; } @@ -209,8 +208,8 @@ txx9_alloc_pci_controller(struct pci_controller *pcic, pcic->mem_offset = 0; /* busaddr == physaddr */ - printk(KERN_INFO "PCI: IO %pR MEM %pR\n", - &pcic->mem_resource[1], &pcic->mem_resource[0]); + pr_info("PCI: IO %pR MEM %pR\n", &pcic->mem_resource[1], + &pcic->mem_resource[0]); /* register_pci_controller() will request MEM resource */ release_resource(&pcic->mem_resource[0]); @@ -219,7 +218,7 @@ txx9_alloc_pci_controller(struct pci_controller *pcic, release_resource(&pcic->mem_resource[0]); free_and_exit: kfree(new); - printk(KERN_ERR "PCI: Failed to allocate resources.\n"); + pr_err("PCI: Failed to allocate resources.\n"); return NULL; } @@ -260,7 +259,7 @@ static int txx9_i8259_irq_setup(int irq) err = request_irq(irq, &i8259_interrupt, IRQF_SHARED, "cascade(i8259)", (void *)(long)irq); if (!err) - printk(KERN_INFO "PCI-ISA bridge PIC (irq %d)\n", irq); + pr_info("PCI-ISA bridge PIC (irq %d)\n", irq); return err; } @@ -308,13 +307,13 @@ static void quirk_slc90e66_ide(struct pci_dev *dev) /* SMSC SLC90E66 IDE uses irq 14, 15 (default) */ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 14); pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &dat); - printk(KERN_INFO "PCI: %s: IRQ %02x", pci_name(dev), dat); + pr_info("PCI: %s: IRQ %02x", pci_name(dev), dat); /* enable SMSC SLC90E66 IDE */ for (i = 0; i < ARRAY_SIZE(regs); i++) { pci_read_config_byte(dev, regs[i], &dat); pci_write_config_byte(dev, regs[i], dat | 0x80); pci_read_config_byte(dev, regs[i], &dat); - printk(KERN_CONT " IDETIM%d %02x", i, dat); + pr_cont(" IDETIM%d %02x", i, dat); } pci_read_config_byte(dev, 0x5c, &dat); /* @@ -329,8 +328,7 @@ static void quirk_slc90e66_ide(struct pci_dev *dev) dat |= 0x01; pci_write_config_byte(dev, 0x5c, dat); pci_read_config_byte(dev, 0x5c, &dat); - printk(KERN_CONT " REG5C %02x", dat); - printk(KERN_CONT "\n"); + pr_cont(" REG5C %02x\n", dat); } #endif /* CONFIG_TOSHIBA_FPCIB0 */ @@ -352,7 +350,7 @@ static void final_fixup(struct pci_dev *dev) (bist & PCI_BIST_CAPABLE)) { unsigned long timeout; pci_set_power_state(dev, PCI_D0); - printk(KERN_INFO "PCI: %s BIST...", pci_name(dev)); + pr_info("PCI: %s BIST...", pci_name(dev)); pci_write_config_byte(dev, PCI_BIST, PCI_BIST_START); timeout = jiffies + HZ * 2; /* timeout after 2 sec */ do { @@ -361,9 +359,9 @@ static void final_fixup(struct pci_dev *dev) break; } while (bist & PCI_BIST_START); if (bist & (PCI_BIST_CODE_MASK | PCI_BIST_START)) - printk(KERN_CONT "failed. (0x%x)\n", bist); + pr_cont("failed. (0x%x)\n", bist); else - printk(KERN_CONT "OK.\n"); + pr_cont("OK.\n"); } } diff --git a/arch/mips/txx9/generic/setup_tx3927.c b/arch/mips/txx9/generic/setup_tx3927.c index d3b83a92cf26..33f7a7253963 100644 --- a/arch/mips/txx9/generic/setup_tx3927.c +++ b/arch/mips/txx9/generic/setup_tx3927.c @@ -67,9 +67,9 @@ void __init tx3927_setup(void) /* do reset on watchdog */ tx3927_ccfgptr->ccfg |= TX3927_CCFG_WR; - printk(KERN_INFO "TX3927 -- CRIR:%08lx CCFG:%08lx PCFG:%08lx\n", - tx3927_ccfgptr->crir, - tx3927_ccfgptr->ccfg, tx3927_ccfgptr->pcfg); + pr_info("TX3927 -- CRIR:%08lx CCFG:%08lx PCFG:%08lx\n", + tx3927_ccfgptr->crir, tx3927_ccfgptr->ccfg, + tx3927_ccfgptr->pcfg); /* TMR */ for (i = 0; i < TX3927_NR_TMR; i++) diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c index 8d8011570b1d..46e9c4101386 100644 --- a/arch/mips/txx9/generic/setup_tx4927.c +++ b/arch/mips/txx9/generic/setup_tx4927.c @@ -183,15 +183,14 @@ void __init tx4927_setup(void) if (!(____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCIARB)) txx9_clear64(&tx4927_ccfgptr->pcfg, TX4927_PCFG_PCICLKEN_ALL); - printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", - txx9_pcode_str, - (cpuclk + 500000) / 1000000, - (txx9_master_clock + 500000) / 1000000, - (__u32)____raw_readq(&tx4927_ccfgptr->crir), - (unsigned long long)____raw_readq(&tx4927_ccfgptr->ccfg), - (unsigned long long)____raw_readq(&tx4927_ccfgptr->pcfg)); + pr_info("%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", + txx9_pcode_str, (cpuclk + 500000) / 1000000, + (txx9_master_clock + 500000) / 1000000, + (__u32)____raw_readq(&tx4927_ccfgptr->crir), + ____raw_readq(&tx4927_ccfgptr->ccfg), + ____raw_readq(&tx4927_ccfgptr->pcfg)); - printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str); + pr_info("%s SDRAMC --", txx9_pcode_str); for (i = 0; i < 4; i++) { __u64 cr = TX4927_SDRAMC_CR(i); unsigned long base, size; @@ -199,15 +198,14 @@ void __init tx4927_setup(void) continue; /* disabled */ base = (unsigned long)(cr >> 49) << 21; size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21; - printk(" CR%d:%016llx", i, (unsigned long long)cr); + pr_cont(" CR%d:%016llx", i, cr); tx4927_sdram_resource[i].name = "SDRAM"; tx4927_sdram_resource[i].start = base; tx4927_sdram_resource[i].end = base + size - 1; tx4927_sdram_resource[i].flags = IORESOURCE_MEM; request_resource(&iomem_resource, &tx4927_sdram_resource[i]); } - printk(" TR:%09llx\n", - (unsigned long long)____raw_readq(&tx4927_sdramcptr->tr)); + pr_cont(" TR:%09llx\n", ____raw_readq(&tx4927_sdramcptr->tr)); /* TMR */ /* disable all timers */ diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c index ba265bf1fd06..85d1795652da 100644 --- a/arch/mips/txx9/generic/setup_tx4938.c +++ b/arch/mips/txx9/generic/setup_tx4938.c @@ -196,15 +196,14 @@ void __init tx4938_setup(void) if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB)) txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL); - printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", - txx9_pcode_str, - (cpuclk + 500000) / 1000000, - (txx9_master_clock + 500000) / 1000000, - (__u32)____raw_readq(&tx4938_ccfgptr->crir), - (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg), - (unsigned long long)____raw_readq(&tx4938_ccfgptr->pcfg)); + pr_info("%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", + txx9_pcode_str, (cpuclk + 500000) / 1000000, + (txx9_master_clock + 500000) / 1000000, + (__u32)____raw_readq(&tx4938_ccfgptr->crir), + ____raw_readq(&tx4938_ccfgptr->ccfg), + ____raw_readq(&tx4938_ccfgptr->pcfg)); - printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str); + pr_info("%s SDRAMC --", txx9_pcode_str); for (i = 0; i < 4; i++) { __u64 cr = TX4938_SDRAMC_CR(i); unsigned long base, size; @@ -212,15 +211,14 @@ void __init tx4938_setup(void) continue; /* disabled */ base = (unsigned long)(cr >> 49) << 21; size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21; - printk(" CR%d:%016llx", i, (unsigned long long)cr); + pr_cont(" CR%d:%016llx", i, cr); tx4938_sdram_resource[i].name = "SDRAM"; tx4938_sdram_resource[i].start = base; tx4938_sdram_resource[i].end = base + size - 1; tx4938_sdram_resource[i].flags = IORESOURCE_MEM; request_resource(&iomem_resource, &tx4938_sdram_resource[i]); } - printk(" TR:%09llx\n", - (unsigned long long)____raw_readq(&tx4938_sdramcptr->tr)); + pr_cont(" TR:%09llx\n", ____raw_readq(&tx4938_sdramcptr->tr)); /* SRAM */ if (txx9_pcode == 0x4938 && ____raw_readq(&tx4938_sramcptr->cr) & 1) { @@ -254,20 +252,20 @@ void __init tx4938_setup(void) txx9_clear64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST); } else { - printk(KERN_INFO "%s: stop PCIC1\n", txx9_pcode_str); + pr_info("%s: stop PCIC1\n", txx9_pcode_str); /* stop PCIC1 */ txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1CKD); } if (!(pcfg & TX4938_PCFG_ETH0_SEL)) { - printk(KERN_INFO "%s: stop ETH0\n", txx9_pcode_str); + pr_info("%s: stop ETH0\n", txx9_pcode_str); txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_ETH0RST); txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_ETH0CKD); } if (!(pcfg & TX4938_PCFG_ETH1_SEL)) { - printk(KERN_INFO "%s: stop ETH1\n", txx9_pcode_str); + pr_info("%s: stop ETH1\n", txx9_pcode_str); txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_ETH1RST); txx9_set64(&tx4938_ccfgptr->clkctr, diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c index 402ac2ec7e83..274928987a21 100644 --- a/arch/mips/txx9/generic/setup_tx4939.c +++ b/arch/mips/txx9/generic/setup_tx4939.c @@ -221,8 +221,8 @@ void __init tx4939_setup(void) (txx9_master_clock + 500000) / 1000000, (txx9_gbus_clock + 500000) / 1000000, (__u32)____raw_readq(&tx4939_ccfgptr->crir), - (unsigned long long)____raw_readq(&tx4939_ccfgptr->ccfg), - (unsigned long long)____raw_readq(&tx4939_ccfgptr->pcfg)); + ____raw_readq(&tx4939_ccfgptr->ccfg), + ____raw_readq(&tx4939_ccfgptr->pcfg)); pr_info("%s DDRC -- EN:%08x", txx9_pcode_str, (__u32)____raw_readq(&tx4939_ddrcptr->winen)); @@ -230,7 +230,7 @@ void __init tx4939_setup(void) __u64 win = ____raw_readq(&tx4939_ddrcptr->win[i]); if (!((__u32)____raw_readq(&tx4939_ddrcptr->winen) & (1 << i))) continue; /* disabled */ - printk(KERN_CONT " #%d:%016llx", i, (unsigned long long)win); + pr_cont(" #%d:%016llx", i, win); tx4939_sdram_resource[i].name = "DDR SDRAM"; tx4939_sdram_resource[i].start = (unsigned long)(win >> 48) << 20; @@ -240,7 +240,7 @@ void __init tx4939_setup(void) tx4939_sdram_resource[i].flags = IORESOURCE_MEM; request_resource(&iomem_resource, &tx4939_sdram_resource[i]); } - printk(KERN_CONT "\n"); + pr_cont("\n"); /* SRAM */ if (____raw_readq(&tx4939_sramcptr->cr) & 1) { diff --git a/arch/mips/txx9/generic/smsc_fdc37m81x.c b/arch/mips/txx9/generic/smsc_fdc37m81x.c index f98baa6263d2..40f4098d3ae1 100644 --- a/arch/mips/txx9/generic/smsc_fdc37m81x.c +++ b/arch/mips/txx9/generic/smsc_fdc37m81x.c @@ -105,9 +105,8 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port) u8 chip_id; if (g_smsc_fdc37m81x_base) - printk(KERN_WARNING "%s: stepping on old base=0x%0*lx\n", - __func__, - field, g_smsc_fdc37m81x_base); + pr_warn("%s: stepping on old base=0x%0*lx\n", __func__, field, + g_smsc_fdc37m81x_base); g_smsc_fdc37m81x_base = port; @@ -117,8 +116,7 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port) if (chip_id == SMSC_FDC37M81X_CHIP_ID) smsc_fdc37m81x_config_end(); else { - printk(KERN_WARNING "%s: unknown chip id 0x%02x\n", __func__, - chip_id); + pr_warn("%s: unknown chip id 0x%02x\n", __func__, chip_id); g_smsc_fdc37m81x_base = 0; } @@ -128,9 +126,8 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port) #ifdef DEBUG static void smsc_fdc37m81x_config_dump_one(const char *key, u8 dev, u8 reg) { - printk(KERN_INFO "%s: dev=0x%02x reg=0x%02x val=0x%02x\n", - key, dev, reg, - smsc_fdc37m81x_rd(reg)); + pr_info("%s: dev=0x%02x reg=0x%02x val=0x%02x\n", key, dev, reg, + smsc_fdc37m81x_rd(reg)); } void smsc_fdc37m81x_config_dump(void) @@ -142,7 +139,7 @@ void smsc_fdc37m81x_config_dump(void) orig = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DNUM); - printk(KERN_INFO "%s: common\n", fname); + pr_info("%s: common\n", fname); smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, SMSC_FDC37M81X_DNUM); smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, @@ -154,7 +151,7 @@ void smsc_fdc37m81x_config_dump(void) smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE, SMSC_FDC37M81X_PMGT); - printk(KERN_INFO "%s: keyboard\n", fname); + pr_info("%s: keyboard\n", fname); smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, SMSC_FDC37M81X_KBD); smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD, SMSC_FDC37M81X_ACTIVE); diff --git a/arch/mips/txx9/jmr3927/prom.c b/arch/mips/txx9/jmr3927/prom.c index c899c0c087a0..68a96473c134 100644 --- a/arch/mips/txx9/jmr3927/prom.c +++ b/arch/mips/txx9/jmr3927/prom.c @@ -45,7 +45,7 @@ void __init jmr3927_prom_init(void) { /* CCFG */ if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0) - printk(KERN_ERR "TX3927 TLB off\n"); + pr_err("TX3927 TLB off\n"); add_memory_region(0, JMR3927_SDRAM_SIZE, BOOT_MEM_RAM); txx9_sio_putchar_init(TX3927_SIO_REG(1)); diff --git a/arch/mips/txx9/jmr3927/setup.c b/arch/mips/txx9/jmr3927/setup.c index a455166dc6d4..613943886e34 100644 --- a/arch/mips/txx9/jmr3927/setup.c +++ b/arch/mips/txx9/jmr3927/setup.c @@ -150,12 +150,11 @@ static void __init jmr3927_board_init(void) jmr3927_led_set(0); - printk(KERN_INFO - "JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n", - jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK, - jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK, - jmr3927_dipsw1(), jmr3927_dipsw2(), - jmr3927_dipsw3(), jmr3927_dipsw4()); + pr_info("JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n", + jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK, + jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK, + jmr3927_dipsw1(), jmr3927_dipsw2(), + jmr3927_dipsw3(), jmr3927_dipsw4()); } /* This trick makes rtc-ds1742 driver usable as is. */ diff --git a/arch/mips/txx9/rbtx4938/setup.c b/arch/mips/txx9/rbtx4938/setup.c index 07939ed6b22f..e68eb2e7ce0c 100644 --- a/arch/mips/txx9/rbtx4938/setup.c +++ b/arch/mips/txx9/rbtx4938/setup.c @@ -123,15 +123,15 @@ static int __init rbtx4938_ethaddr_init(void) /* 0-3: "MAC\0", 4-9:eth0, 10-15:eth1, 16:sum */ if (spi_eeprom_read(SPI_BUSNO, SEEPROM1_CS, 0, dat, sizeof(dat))) { - printk(KERN_ERR "seeprom: read error.\n"); + pr_err("seeprom: read error.\n"); return -ENODEV; } else { if (strcmp(dat, "MAC") != 0) - printk(KERN_WARNING "seeprom: bad signature.\n"); + pr_warn("seeprom: bad signature.\n"); for (i = 0, sum = 0; i < sizeof(dat); i++) sum += dat[i]; if (sum) - printk(KERN_WARNING "seeprom: bad checksum.\n"); + pr_warn("seeprom: bad checksum.\n"); } tx4938_ethaddr_init(&dat[4], &dat[4 + 6]); #endif /* CONFIG_PCI */ @@ -214,14 +214,14 @@ static void __init rbtx4938_mem_setup(void) rbtx4938_fpga_resource.end = CPHYSADDR(RBTX4938_FPGA_REG_ADDR) + 0xffff; rbtx4938_fpga_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY; if (request_resource(&txx9_ce_res[2], &rbtx4938_fpga_resource)) - printk(KERN_ERR "request resource for fpga failed\n"); + pr_err("request resource for fpga failed\n"); _machine_restart = rbtx4938_machine_restart; writeb(0xff, rbtx4938_led_addr); - printk(KERN_INFO "RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n", - readb(rbtx4938_fpga_rev_addr), - readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr)); + pr_info("RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n", + readb(rbtx4938_fpga_rev_addr), + readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr)); } static void __init rbtx4938_ne_init(void) From e4c64e6f3dd38cb902c9a304a1fa6c1bdd0da67c Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Fri, 25 Nov 2016 13:36:18 +0100 Subject: [PATCH 0092/1587] MIPS: Zboot: Don't use $(LINUXINCLUDE) twice The make variables KBUILD_CFLAGS and KBUILD_AFLAGS both contain $(LINUXINCLUDE). But the build already picks up $(LINUXINCLUDE) from scripts/Makefile.lib. The net effect is that the (long) list of include directories is used twice. This is harmless but pointless. So stop using $(LINUXINCLUDE) twice. Signed-off-by: Paul Bolle Cc: Masahiro Yamada Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14622/ Signed-off-by: Ralf Baechle --- arch/mips/boot/compressed/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 011b14512c05..41564a4db6f7 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -22,10 +22,10 @@ KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//") KBUILD_CFLAGS := $(filter-out -fstack-protector, $(KBUILD_CFLAGS)) -KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \ +KBUILD_CFLAGS := $(KBUILD_CFLAGS) -D__KERNEL__ \ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull" -KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ +KBUILD_AFLAGS := $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \ -DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS) From f9f1c8db1c37253805eaa32265e1e1af3ae7d0a4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 15 Dec 2016 12:27:21 +0100 Subject: [PATCH 0093/1587] MIPS: IP22: Reformat inline assembler code to modern standards. Signed-off-by: Ralf Baechle --- arch/mips/mm/sc-ip22.c | 43 ++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c index 026cb59a914d..610f44b4d764 100644 --- a/arch/mips/mm/sc-ip22.c +++ b/arch/mips/mm/sc-ip22.c @@ -31,26 +31,29 @@ static inline void indy_sc_wipe(unsigned long first, unsigned long last) unsigned long tmp; __asm__ __volatile__( - ".set\tpush\t\t\t# indy_sc_wipe\n\t" - ".set\tnoreorder\n\t" - ".set\tmips3\n\t" - ".set\tnoat\n\t" - "mfc0\t%2, $12\n\t" - "li\t$1, 0x80\t\t\t# Go 64 bit\n\t" - "mtc0\t$1, $12\n\t" - - "dli\t$1, 0x9000000080000000\n\t" - "or\t%0, $1\t\t\t# first line to flush\n\t" - "or\t%1, $1\t\t\t# last line to flush\n\t" - ".set\tat\n\t" - - "1:\tsw\t$0, 0(%0)\n\t" - "bne\t%0, %1, 1b\n\t" - " daddu\t%0, 32\n\t" - - "mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t" - "nop; nop; nop; nop;\n\t" - ".set\tpop" + " .set push # indy_sc_wipe \n" + " .set noreorder \n" + " .set mips3 \n" + " .set noat \n" + " mfc0 %2, $12 \n" + " li $1, 0x80 # Go 64 bit \n" + " mtc0 $1, $12 \n" + " \n" + " dli $1, 0x9000000080000000 \n" + " or %0, $1 # first line to flush \n" + " or %1, $1 # last line to flush \n" + " .set at \n" + " \n" + "1: sw $0, 0(%0) \n" + " bne %0, %1, 1b \n" + " daddu %0, 32 \n" + " \n" + " mtc0 %2, $12 # Back to 32 bit \n" + " nop # pipeline hazard \n" + " nop \n" + " nop \n" + " nop \n" + " .set pop \n" : "=r" (first), "=r" (last), "=&r" (tmp) : "0" (first), "1" (last)); } From ae2f5e5ed04a17c1aa1f0a3714c725e12c21d2a9 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 15 Dec 2016 12:39:22 +0100 Subject: [PATCH 0094/1587] MIPS: IP22: Fix build error due to binutils 2.25 uselessnes. Fix the following build error with binutils 2.25. CC arch/mips/mm/sc-ip22.o {standard input}: Assembler messages: {standard input}:132: Error: number (0x9000000080000000) larger than 32 bits {standard input}:159: Error: number (0x9000000080000000) larger than 32 bits {standard input}:200: Error: number (0x9000000080000000) larger than 32 bits scripts/Makefile.build:293: recipe for target 'arch/mips/mm/sc-ip22.o' failed make[1]: *** [arch/mips/mm/sc-ip22.o] Error 1 MIPS has used .set mips3 to temporarily switch the assembler to 64 bit mode in 64 bit kernels virtually forever. Binutils 2.25 broke this behavious partially by happily accepting 64 bit instructions in .set mips3 mode but puking on 64 bit constants when generating 32 bit ELF. Binutils 2.26 restored the old behaviour again. Fix build with binutils 2.25 by open coding the offending dli $1, 0x9000000080000000 as li $1, 0x9000 dsll $1, $1, 48 which is ugly be the only thing that will build on all binutils vintages. Signed-off-by: Ralf Baechle Cc: stable@vger.kernel.org --- arch/mips/mm/sc-ip22.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c index 610f44b4d764..f293a97cb885 100644 --- a/arch/mips/mm/sc-ip22.c +++ b/arch/mips/mm/sc-ip22.c @@ -39,7 +39,18 @@ static inline void indy_sc_wipe(unsigned long first, unsigned long last) " li $1, 0x80 # Go 64 bit \n" " mtc0 $1, $12 \n" " \n" - " dli $1, 0x9000000080000000 \n" + " # \n" + " # Open code a dli $1, 0x9000000080000000 \n" + " # \n" + " # Required because binutils 2.25 will happily accept \n" + " # 64 bit instructions in .set mips3 mode but puke on \n" + " # 64 bit constants when generating 32 bit ELF \n" + " # \n" + " lui $1,0x9000 \n" + " dsll $1,$1,0x10 \n" + " ori $1,$1,0x8000 \n" + " dsll $1,$1,0x10 \n" + " \n" " or %0, $1 # first line to flush \n" " or %1, $1 # last line to flush \n" " .set at \n" From fe8bd18ffea5327344d4ec2bf11f47951212abd0 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 19 Dec 2016 14:20:56 +0000 Subject: [PATCH 0095/1587] MIPS: Introduce irq_stack Allocate a per-cpu irq stack for use within interrupt handlers. Also add a utility function on_irq_stack to determine if a given stack pointer is within the irq stack for that cpu. Signed-off-by: Matt Redfearn Acked-by: Jason A. Donenfeld Cc: Thomas Gleixner Cc: Paolo Bonzini Cc: Chris Metcalf Cc: Petr Mladek Cc: James Hogan Cc: Paul Burton Cc: Aaron Tomlin Cc: Andrew Morton Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14740/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/irq.h | 12 ++++++++++++ arch/mips/kernel/asm-offsets.c | 1 + arch/mips/kernel/irq.c | 11 +++++++++++ 3 files changed, 24 insertions(+) diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 6bf10e796553..956db6e201d1 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -17,6 +17,18 @@ #include +#define IRQ_STACK_SIZE THREAD_SIZE + +extern void *irq_stack[NR_CPUS]; + +static inline bool on_irq_stack(int cpu, unsigned long sp) +{ + unsigned long low = (unsigned long)irq_stack[cpu]; + unsigned long high = low + IRQ_STACK_SIZE; + + return (low <= sp && sp <= high); +} + #ifdef CONFIG_I8259 static inline int irq_canonicalize(int irq) { diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 6080582a26d1..a7277698d328 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -102,6 +102,7 @@ void output_thread_info_defines(void) OFFSET(TI_REGS, thread_info, regs); DEFINE(_THREAD_SIZE, THREAD_SIZE); DEFINE(_THREAD_MASK, THREAD_MASK); + DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE); BLANK(); } diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index f8f5836eb3c1..ba150c755fcc 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -25,6 +25,8 @@ #include #include +void *irq_stack[NR_CPUS]; + /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves. @@ -58,6 +60,15 @@ void __init init_IRQ(void) clear_c0_status(ST0_IM); arch_init_irq(); + + for_each_possible_cpu(i) { + int irq_pages = IRQ_STACK_SIZE / PAGE_SIZE; + void *s = (void *)__get_free_pages(GFP_KERNEL, irq_pages); + + irq_stack[i] = s; + pr_debug("CPU%d IRQ stack at 0x%p - 0x%p\n", i, + irq_stack[i], irq_stack[i] + IRQ_STACK_SIZE); + } } #ifdef CONFIG_DEBUG_STACKOVERFLOW From d42d8d106b0275b027c1e8992c42aecf933436ea Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 19 Dec 2016 14:20:57 +0000 Subject: [PATCH 0096/1587] MIPS: Stack unwinding while on IRQ stack Within unwind stack, check if the stack pointer being unwound is within the CPU's irq_stack and if so use that page rather than the task's stack page. Signed-off-by: Matt Redfearn Acked-by: Jason A. Donenfeld Cc: Thomas Gleixner Cc: Adam Buchbinder Cc: Maciej W. Rozycki Cc: Marcin Nowakowski Cc: Chris Metcalf Cc: James Hogan Cc: Paul Burton Cc: Jiri Slaby Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14741/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 5142b1dfe8a7..48e30e0469ef 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -511,7 +512,19 @@ EXPORT_SYMBOL(unwind_stack_by_address); unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, unsigned long pc, unsigned long *ra) { - unsigned long stack_page = (unsigned long)task_stack_page(task); + unsigned long stack_page = 0; + int cpu; + + for_each_possible_cpu(cpu) { + if (on_irq_stack(cpu, *sp)) { + stack_page = (unsigned long)irq_stack[cpu]; + break; + } + } + + if (!stack_page) + stack_page = (unsigned long)task_stack_page(task); + return unwind_stack_by_address(stack_page, sp, pc, ra); } #endif From 510d86362a27577f5ee23f46cfb354ad49731e61 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 19 Dec 2016 14:20:58 +0000 Subject: [PATCH 0097/1587] MIPS: Only change $28 to thread_info if coming from user mode The SAVE_SOME macro is used to save the execution context on all exceptions. If an exception occurs while executing user code, the stack is switched to the kernel's stack for the current task, and register $28 is switched to point to the current_thread_info, which is at the bottom of the stack region. If the exception occurs while executing kernel code, the stack is left, and this change ensures that register $28 is not updated. This is the correct behaviour when the kernel can be executing on the separate irq stack, because the thread_info will not be at the base of it. With this change, register $28 is only switched to it's kernel conventional usage of the currrent thread info pointer at the point at which execution enters kernel space. Doing it on every exception was redundant, but OK without an IRQ stack, but will be erroneous once that is introduced. Signed-off-by: Matt Redfearn Acked-by: Jason A. Donenfeld Cc: Thomas Gleixner Cc: James Hogan Cc: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14742/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/stackframe.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h index eebf39549606..2f182bdf024f 100644 --- a/arch/mips/include/asm/stackframe.h +++ b/arch/mips/include/asm/stackframe.h @@ -216,12 +216,19 @@ LONG_S $25, PT_R25(sp) LONG_S $28, PT_R28(sp) LONG_S $31, PT_R31(sp) + + /* Set thread_info if we're coming from user mode */ + mfc0 k0, CP0_STATUS + sll k0, 3 /* extract cu0 bit */ + bltz k0, 9f + ori $28, sp, _THREAD_MASK xori $28, _THREAD_MASK #ifdef CONFIG_CPU_CAVIUM_OCTEON .set mips64 pref 0, 0($28) /* Prefetch the current pointer */ #endif +9: .set pop .endm From dda45f701c9d7ad4ac0bb446e3a96f6df9a468d9 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 19 Dec 2016 14:20:59 +0000 Subject: [PATCH 0098/1587] MIPS: Switch to the irq_stack in interrupts When enterring interrupt context via handle_int or except_vec_vi, switch to the irq_stack of the current CPU if it is not already in use. The current stack pointer is masked with the thread size and compared to the base or the irq stack. If it does not match then the stack pointer is set to the top of that stack, otherwise this is a nested irq being handled on the irq stack so the stack pointer should be left as it was. The in-use stack pointer is placed in the callee saved register s1. It will be saved to the stack when plat_irq_dispatch is invoked and can be restored once control returns here. Signed-off-by: Matt Redfearn Acked-by: Jason A. Donenfeld Cc: Thomas Gleixner Cc: James Hogan Cc: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14743/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/genex.S | 81 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index dc0b29612891..0a7ba4b2f687 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -187,9 +187,44 @@ NESTED(handle_int, PT_SIZE, sp) LONG_L s0, TI_REGS($28) LONG_S sp, TI_REGS($28) - PTR_LA ra, ret_from_irq - PTR_LA v0, plat_irq_dispatch - jr v0 + + /* + * SAVE_ALL ensures we are using a valid kernel stack for the thread. + * Check if we are already using the IRQ stack. + */ + move s1, sp # Preserve the sp + + /* Get IRQ stack for this CPU */ + ASM_CPUID_MFC0 k0, ASM_SMP_CPUID_REG +#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) + lui k1, %hi(irq_stack) +#else + lui k1, %highest(irq_stack) + daddiu k1, %higher(irq_stack) + dsll k1, 16 + daddiu k1, %hi(irq_stack) + dsll k1, 16 +#endif + LONG_SRL k0, SMP_CPUID_PTRSHIFT + LONG_ADDU k1, k0 + LONG_L t0, %lo(irq_stack)(k1) + + # Check if already on IRQ stack + PTR_LI t1, ~(_THREAD_SIZE-1) + and t1, t1, sp + beq t0, t1, 2f + + /* Switch to IRQ stack */ + li t1, _IRQ_STACK_SIZE + PTR_ADD sp, t0, t1 + +2: + jal plat_irq_dispatch + + /* Restore sp */ + move sp, s1 + + j ret_from_irq #ifdef CONFIG_CPU_MICROMIPS nop #endif @@ -262,8 +297,44 @@ NESTED(except_vec_vi_handler, 0, sp) LONG_L s0, TI_REGS($28) LONG_S sp, TI_REGS($28) - PTR_LA ra, ret_from_irq - jr v0 + + /* + * SAVE_ALL ensures we are using a valid kernel stack for the thread. + * Check if we are already using the IRQ stack. + */ + move s1, sp # Preserve the sp + + /* Get IRQ stack for this CPU */ + ASM_CPUID_MFC0 k0, ASM_SMP_CPUID_REG +#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) + lui k1, %hi(irq_stack) +#else + lui k1, %highest(irq_stack) + daddiu k1, %higher(irq_stack) + dsll k1, 16 + daddiu k1, %hi(irq_stack) + dsll k1, 16 +#endif + LONG_SRL k0, SMP_CPUID_PTRSHIFT + LONG_ADDU k1, k0 + LONG_L t0, %lo(irq_stack)(k1) + + # Check if already on IRQ stack + PTR_LI t1, ~(_THREAD_SIZE-1) + and t1, t1, sp + beq t0, t1, 2f + + /* Switch to IRQ stack */ + li t1, _IRQ_STACK_SIZE + PTR_ADD sp, t0, t1 + +2: + jal plat_irq_dispatch + + /* Restore sp */ + move sp, s1 + + j ret_from_irq END(except_vec_vi_handler) /* From 3cc3434fd6307d06b53b98ce83e76bf9807689b9 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 19 Dec 2016 14:21:00 +0000 Subject: [PATCH 0099/1587] MIPS: Select HAVE_IRQ_EXIT_ON_IRQ_STACK Since do_IRQ is now invoked on a separate IRQ stack, we select HAVE_IRQ_EXIT_ON_IRQ_STACK so that softirq's may be invoked directly from irq_exit(), rather than requiring do_softirq_own_stack. Signed-off-by: Matt Redfearn Acked-by: Jason A. Donenfeld Cc: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14744/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b3c5bde43d34..80832aa8e4fb 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -9,6 +9,7 @@ config MIPS select HAVE_CONTEXT_TRACKING select HAVE_GENERIC_DMA_COHERENT select HAVE_IDE + select HAVE_IRQ_EXIT_ON_IRQ_STACK select HAVE_OPROFILE select HAVE_PERF_EVENTS select PERF_USE_VMALLOC From 715e20eb41cc8b48f92d959da2faaac61d110349 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Tue, 22 Nov 2016 13:44:10 -0600 Subject: [PATCH 0100/1587] MIPS: Octeon: Add fw_init_cmdline() for Cavium platforms. Add platform-specific kernel command line processing for Octeon. Signed-off-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14599/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/setup.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 9a2db1c013d9..4809ce4719d1 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -949,6 +949,22 @@ static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size) } #endif /* CONFIG_CRASH_DUMP */ +void __init fw_init_cmdline(void) +{ + int i; + + octeon_boot_desc_ptr = (struct octeon_boot_descriptor *)fw_arg3; + for (i = 0; i < octeon_boot_desc_ptr->argc; i++) { + const char *arg = + cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]); + if (strlen(arcs_cmdline) + strlen(arg) + 1 < + sizeof(arcs_cmdline) - 1) { + strcat(arcs_cmdline, " "); + strcat(arcs_cmdline, arg); + } + } +} + void __init plat_mem_setup(void) { uint64_t mem_alloc_size; From 126c1113bf3e6facdd5562064043b9e8fa8c9bf1 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Tue, 22 Nov 2016 13:44:20 -0600 Subject: [PATCH 0101/1587] MIPS: Octeon: Add plat_get_fdt() function for Cavium platforms. Add in the function needed for Octeon platforms to support KASLR. Signed-off-by: Steven J. Hill Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/setup.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 4809ce4719d1..d9dbeb0b165b 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -965,6 +965,13 @@ void __init fw_init_cmdline(void) } } +void __init *plat_get_fdt(void) +{ + octeon_bootinfo = + cvmx_phys_to_ptr(octeon_boot_desc_ptr->cvmx_desc_vaddr); + return phys_to_virt(octeon_bootinfo->fdt_addr); +} + void __init plat_mem_setup(void) { uint64_t mem_alloc_size; From 3ff72be4c9ce269c5b7adff9b0f912a2df3cb987 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Tue, 13 Dec 2016 14:25:37 -0600 Subject: [PATCH 0102/1587] MIPS: Octeon: Enable KASLR This patch enables KASLR for Octeon systems. The SMP startup code is such that the secondaries monitor the volatile variable 'octeon_processor_relocated_kernel_entry' for any non-zero value. The 'plat_post_relocation hook' is used to set that value to the kernel entry point of the relocated kernel. The secondary CPUs will then jusmp to the new kernel, perform their initialization again and begin waiting for the boot CPU to start them via the relocated loop 'octeon_spin_wait_boot'. Inspired by Steven's code from Cavium. Signed-off-by: Matt Redfearn Signed-off-by: Steven J. Hill Acked-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14669/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 3 ++- arch/mips/cavium-octeon/smp.c | 20 +++++++++++++++++-- .../mach-cavium-octeon/kernel-entry-init.h | 15 ++++++++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 80832aa8e4fb..7cb4b0e5f49a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -910,6 +910,7 @@ config CAVIUM_OCTEON_SOC select NR_CPUS_DEFAULT_16 select BUILTIN_DTB select MTD_COMPLEX_MAPPINGS + select SYS_SUPPORTS_RELOCATABLE help This option supports all of the Octeon reference boards from Cavium Networks. It builds a kernel that dynamically determines the Octeon @@ -2571,7 +2572,7 @@ config SYS_SUPPORTS_NUMA config RELOCATABLE bool "Relocatable kernel" - depends on SYS_SUPPORTS_RELOCATABLE && (CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_MIPS32_R6 || CPU_MIPS64_R6) + depends on SYS_SUPPORTS_RELOCATABLE && (CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_MIPS32_R6 || CPU_MIPS64_R6 || CAVIUM_OCTEON_SOC) help This builds a kernel image that retains relocation information so it can be loaded someplace besides the default 1MB. diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 256fe6f65cf2..889c3f49dbc0 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -24,12 +24,17 @@ volatile unsigned long octeon_processor_boot = 0xff; volatile unsigned long octeon_processor_sp; volatile unsigned long octeon_processor_gp; +#ifdef CONFIG_RELOCATABLE +volatile unsigned long octeon_processor_relocated_kernel_entry; +#endif /* CONFIG_RELOCATABLE */ #ifdef CONFIG_HOTPLUG_CPU uint64_t octeon_bootloader_entry_addr; EXPORT_SYMBOL(octeon_bootloader_entry_addr); #endif +extern void kernel_entry(unsigned long arg1, ...); + static void octeon_icache_flush(void) { asm volatile ("synci 0($0)\n"); @@ -180,6 +185,19 @@ static void __init octeon_smp_setup(void) octeon_smp_hotplug_setup(); } + +#ifdef CONFIG_RELOCATABLE +int plat_post_relocation(long offset) +{ + unsigned long entry = (unsigned long)kernel_entry; + + /* Send secondaries into relocated kernel */ + octeon_processor_relocated_kernel_entry = entry + offset; + + return 0; +} +#endif /* CONFIG_RELOCATABLE */ + /** * Firmware CPU startup hook * @@ -333,8 +351,6 @@ void play_dead(void) ; } -extern void kernel_entry(unsigned long arg1, ...); - static void start_after_reset(void) { kernel_entry(0, 0, 0); /* set a2 = 0 for secondary core */ diff --git a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h index c4873e8594ef..c38b38ce5a3d 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h @@ -99,9 +99,20 @@ # to begin # - # This is the variable where the next core to boot os stored - PTR_LA t0, octeon_processor_boot octeon_spin_wait_boot: +#ifdef CONFIG_RELOCATABLE + PTR_LA t0, octeon_processor_relocated_kernel_entry + LONG_L t0, (t0) + beq zero, t0, 1f + nop + + jr t0 + nop +1: +#endif /* CONFIG_RELOCATABLE */ + + # This is the variable where the next core to boot is stored + PTR_LA t0, octeon_processor_boot # Get the core id of the next to be booted LONG_L t1, (t0) # Keep looping if it isn't me From 8cc709d7d4f013f51d38ceb2e3c8c82d230cf457 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Fri, 9 Dec 2016 02:36:22 -0600 Subject: [PATCH 0103/1587] MIPS: Relocatable: Provide plat_post_relocation hook This hook provides the platform the chance to perform any required setup before the boot processor switches to the relocated kernel. The relocated kernel has been copied and fixed up ready for execution at this point. Secondary CPUs may wish to switch to it early. There is also the opportunity for the platform to abort jumping to the relocated kernel if there is anything wrong with the chosen offset. Signed-off-by: Matt Redfearn Signed-off-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14651/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/relocate.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c index 1958910b75c0..c82288569eb1 100644 --- a/arch/mips/kernel/relocate.c +++ b/arch/mips/kernel/relocate.c @@ -31,6 +31,17 @@ extern u32 _relocation_end[]; /* End relocation table */ extern long __start___ex_table; /* Start exception table */ extern long __stop___ex_table; /* End exception table */ +/* + * This function may be defined for a platform to perform any post-relocation + * fixup necessary. + * Return non-zero to abort relocation + */ +int __weak plat_post_relocation(long offset) +{ + return 0; +} + + static inline u32 __init get_synci_step(void) { u32 res; @@ -338,6 +349,15 @@ void *__init relocate_kernel(void) */ memcpy(RELOCATED(&__bss_start), &__bss_start, bss_length); + /* + * Last chance for the platform to abort relocation. + * This may also be used by the platform to perform any + * initialisation required now that the new kernel is + * resident in memory and ready to be executed. + */ + if (plat_post_relocation(offset)) + goto out; + /* The current thread is now within the relocated image */ __current_thread_info = RELOCATED(&init_thread_union); From 3f00f4d8f083bc61005d0a1ef592b149f5c88bbd Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:52:19 +0000 Subject: [PATCH 0104/1587] MIPS: Ensure bss section ends on a long-aligned address When clearing the .bss section in kernel_entry we do so using LONG_S instructions, and branch whilst the current write address doesn't equal the end of the .bss section minus the size of a long integer. The .bss section always begins at a long-aligned address and we always increment the write pointer by the size of a long integer - we therefore rely upon the .bss section ending at a long-aligned address. If this is not the case then the long-aligned write address can never be equal to the non-long-aligned end address & we will continue to increment past the end of the .bss section, attempting to zero the rest of memory. Despite this requirement that .bss end at a long-aligned address we pass 0 as the end alignment requirement to the BSS_SECTION macro and thus don't guarantee any particular alignment, allowing us to hit the error condition described above. Fix this by instead passing 8 bytes as the end alignment argument to the BSS_SECTION macro, ensuring that the end of the .bss section is always at least long-aligned. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14526/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/vmlinux.lds.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index d5de67591735..f0a0e6d62be3 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -182,7 +182,7 @@ SECTIONS * Force .bss to 64K alignment so that .bss..swapper_pg_dir * gets that alignment. .sbss should be empty, so there will be * no holes after __init_end. */ - BSS_SECTION(0, 0x10000, 0) + BSS_SECTION(0, 0x10000, 8) _end = . ; From ca0c40c38c3bd9be82601cc5623ea4cc8addc236 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 17 Oct 2016 15:56:21 +0100 Subject: [PATCH 0105/1587] MIPS: Use generic asm/unaligned.h The MIPS-specific asm/unaligned.h provides nothing that the generic version doesn't - it simply uses MIPS-specific endianness macros in place of generic ones & lacks support for CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS. Remove it & switch to using the generic version to remove duplication. Signed-off-by: Paul Burton Reviewed-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14412/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/Kbuild | 1 + arch/mips/include/asm/unaligned.h | 28 ---------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 arch/mips/include/asm/unaligned.h diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index 3269b742a75e..45b0d6568270 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -16,6 +16,7 @@ generic-y += sections.h generic-y += segment.h generic-y += serial.h generic-y += trace_clock.h +generic-y += unaligned.h generic-y += user.h generic-y += word-at-a-time.h generic-y += xor.h diff --git a/arch/mips/include/asm/unaligned.h b/arch/mips/include/asm/unaligned.h deleted file mode 100644 index 42f66c311473..000000000000 --- a/arch/mips/include/asm/unaligned.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) - */ -#ifndef _ASM_MIPS_UNALIGNED_H -#define _ASM_MIPS_UNALIGNED_H - -#include -#if defined(__MIPSEB__) -# include -# include -# define get_unaligned __get_unaligned_be -# define put_unaligned __put_unaligned_be -#elif defined(__MIPSEL__) -# include -# include -# define get_unaligned __get_unaligned_le -# define put_unaligned __put_unaligned_le -#else -# error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???" -#endif - -# include - -#endif /* _ASM_MIPS_UNALIGNED_H */ From ccaf7caf2c73c6db920772bf08bf1d47b2170634 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 15:07:02 +0000 Subject: [PATCH 0106/1587] MIPS: Clear ISA bit correctly in get_frame_info() get_frame_info() can be called in microMIPS kernels with the ISA bit already clear. For example this happens when unwind_stack_by_address() is called because we begin with a PC that has the ISA bit set & subtract the (odd) offset from the preceding symbol (which does not have the ISA bit set). Since get_frame_info() unconditionally subtracts 1 from the PC in microMIPS kernels it incorrectly misaligns the address it then attempts to access code at, leading to an address error exception. Fix this by using msk_isa16_mode() to clear the ISA bit, which allows get_frame_info() to function regardless of whether it is provided with a PC that has the ISA bit set or not. Signed-off-by: Paul Burton Fixes: 34c2f668d0f6 ("MIPS: microMIPS: Add unaligned access support.") Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Cc: # v3.10+ Patchwork: https://patchwork.linux-mips.org/patch/14528/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 48e30e0469ef..213278dbbc04 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -304,17 +304,14 @@ static inline int is_sp_move_ins(union mips_instruction *ip) static int get_frame_info(struct mips_frame_info *info) { -#ifdef CONFIG_CPU_MICROMIPS - union mips_instruction *ip = (void *) (((char *) info->func) - 1); -#else - union mips_instruction *ip = info->func; -#endif + union mips_instruction *ip; unsigned max_insns = info->func_size / sizeof(union mips_instruction); unsigned i; info->pc_offset = -1; info->frame_size = 0; + ip = (void *)msk_isa16_mode((ulong)info->func); if (!ip) goto err; From a3552dace7d1d0cabf573e88fc3025cb90c4a601 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 15:07:03 +0000 Subject: [PATCH 0107/1587] MIPS: Prevent unaligned accesses during stack unwinding During stack unwinding we call a number of functions to determine what type of instruction we're looking at. The union mips_instruction pointer provided to them may be pointing at a 2 byte, but not 4 byte, aligned address & we thus cannot directly access the 4 byte wide members of the union mips_instruction. To avoid this is_ra_save_ins() copies the required half-words of the microMIPS instruction to a correctly aligned union mips_instruction on the stack, which it can then access safely. The is_jump_ins() & is_sp_move_ins() functions do not correctly perform this temporary copy, and instead attempt to directly dereference 4 byte fields which may be misaligned and lead to an address exception. Fix this by copying the instruction halfwords to a temporary union mips_instruction in get_frame_info() such that we can provide a 4 byte aligned union mips_instruction to the is_*_ins() functions and they do not need to deal with misalignment themselves. Signed-off-by: Paul Burton Fixes: 34c2f668d0f6 ("MIPS: microMIPS: Add unaligned access support.") Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Cc: # v3.10+ Patchwork: https://patchwork.linux-mips.org/patch/14529/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 70 +++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 213278dbbc04..8dddaef1a345 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -199,8 +199,6 @@ struct mips_frame_info { static inline int is_ra_save_ins(union mips_instruction *ip) { #ifdef CONFIG_CPU_MICROMIPS - union mips_instruction mmi; - /* * swsp ra,offset * swm16 reglist,offset(sp) @@ -210,23 +208,20 @@ static inline int is_ra_save_ins(union mips_instruction *ip) * * microMIPS is way more fun... */ - if (mm_insn_16bit(ip->halfword[0])) { - mmi.word = (ip->halfword[0] << 16); - return (mmi.mm16_r5_format.opcode == mm_swsp16_op && - mmi.mm16_r5_format.rt == 31) || - (mmi.mm16_m_format.opcode == mm_pool16c_op && - mmi.mm16_m_format.func == mm_swm16_op); + if (mm_insn_16bit(ip->halfword[1])) { + return (ip->mm16_r5_format.opcode == mm_swsp16_op && + ip->mm16_r5_format.rt == 31) || + (ip->mm16_m_format.opcode == mm_pool16c_op && + ip->mm16_m_format.func == mm_swm16_op); } else { - mmi.halfword[0] = ip->halfword[1]; - mmi.halfword[1] = ip->halfword[0]; - return (mmi.mm_m_format.opcode == mm_pool32b_op && - mmi.mm_m_format.rd > 9 && - mmi.mm_m_format.base == 29 && - mmi.mm_m_format.func == mm_swm32_func) || - (mmi.i_format.opcode == mm_sw32_op && - mmi.i_format.rs == 29 && - mmi.i_format.rt == 31); + return (ip->mm_m_format.opcode == mm_pool32b_op && + ip->mm_m_format.rd > 9 && + ip->mm_m_format.base == 29 && + ip->mm_m_format.func == mm_swm32_func) || + (ip->i_format.opcode == mm_sw32_op && + ip->i_format.rs == 29 && + ip->i_format.rt == 31); } #else /* sw / sd $ra, offset($sp) */ @@ -247,12 +242,8 @@ static inline int is_jump_ins(union mips_instruction *ip) * * microMIPS is kind of more fun... */ - union mips_instruction mmi; - - mmi.word = (ip->halfword[0] << 16); - - if ((mmi.mm16_r5_format.opcode == mm_pool16c_op && - (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) || + if ((ip->mm16_r5_format.opcode == mm_pool16c_op && + (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) || ip->j_format.opcode == mm_jal32_op) return 1; if (ip->r_format.opcode != mm_pool32a_op || @@ -281,15 +272,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip) * * microMIPS is not more fun... */ - if (mm_insn_16bit(ip->halfword[0])) { - union mips_instruction mmi; - - mmi.word = (ip->halfword[0] << 16); - return (mmi.mm16_r3_format.opcode == mm_pool16d_op && - mmi.mm16_r3_format.simmediate && mm_addiusp_func) || - (mmi.mm16_r5_format.opcode == mm_pool16d_op && - mmi.mm16_r5_format.rt == 29); + if (mm_insn_16bit(ip->halfword[1])) { + return (ip->mm16_r3_format.opcode == mm_pool16d_op && + ip->mm16_r3_format.simmediate && mm_addiusp_func) || + (ip->mm16_r5_format.opcode == mm_pool16d_op && + ip->mm16_r5_format.rt == 29); } + return ip->mm_i_format.opcode == mm_addiu32_op && ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29; #else @@ -304,7 +293,8 @@ static inline int is_sp_move_ins(union mips_instruction *ip) static int get_frame_info(struct mips_frame_info *info) { - union mips_instruction *ip; + bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS); + union mips_instruction insn, *ip; unsigned max_insns = info->func_size / sizeof(union mips_instruction); unsigned i; @@ -320,11 +310,21 @@ static int get_frame_info(struct mips_frame_info *info) max_insns = min(128U, max_insns); for (i = 0; i < max_insns; i++, ip++) { + if (is_mmips && mm_insn_16bit(ip->halfword[0])) { + insn.halfword[0] = 0; + insn.halfword[1] = ip->halfword[0]; + } else if (is_mmips) { + insn.halfword[0] = ip->halfword[1]; + insn.halfword[1] = ip->halfword[0]; + } else { + insn.word = ip->word; + } - if (is_jump_ins(ip)) + if (is_jump_ins(&insn)) break; + if (!info->frame_size) { - if (is_sp_move_ins(ip)) + if (is_sp_move_ins(&insn)) { #ifdef CONFIG_CPU_MICROMIPS if (mm_insn_16bit(ip->halfword[0])) @@ -347,7 +347,7 @@ static int get_frame_info(struct mips_frame_info *info) } continue; } - if (info->pc_offset == -1 && is_ra_save_ins(ip)) { + if (info->pc_offset == -1 && is_ra_save_ins(&insn)) { info->pc_offset = ip->i_format.simmediate / sizeof(long); break; From b6c7a324df37bf05ef7a2c1580683cf10d082d97 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 15:07:04 +0000 Subject: [PATCH 0108/1587] MIPS: Fix get_frame_info() handling of microMIPS function size get_frame_info() is meant to iterate over up to the first 128 instructions within a function, but for microMIPS kernels it will not reach that many instructions unless the function is 512 bytes long since we calculate the maximum number of instructions to check by dividing the function length by the 4 byte size of a union mips_instruction. In microMIPS kernels this won't do since instructions are variable length. Fix this by instead checking whether the pointer to the current instruction has reached the end of the function, and use max_insns as a simple constant to check the number of iterations against. Signed-off-by: Paul Burton Fixes: 34c2f668d0f6 ("MIPS: microMIPS: Add unaligned access support.") Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Cc: # v3.10+ Patchwork: https://patchwork.linux-mips.org/patch/14530/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 8dddaef1a345..9f7a19ca1d4c 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -294,9 +294,9 @@ static inline int is_sp_move_ins(union mips_instruction *ip) static int get_frame_info(struct mips_frame_info *info) { bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS); - union mips_instruction insn, *ip; - unsigned max_insns = info->func_size / sizeof(union mips_instruction); - unsigned i; + union mips_instruction insn, *ip, *ip_end; + const unsigned int max_insns = 128; + unsigned int i; info->pc_offset = -1; info->frame_size = 0; @@ -305,11 +305,9 @@ static int get_frame_info(struct mips_frame_info *info) if (!ip) goto err; - if (max_insns == 0) - max_insns = 128U; /* unknown function size */ - max_insns = min(128U, max_insns); + ip_end = (void *)ip + info->func_size; - for (i = 0; i < max_insns; i++, ip++) { + for (i = 0; i < max_insns && ip < ip_end; i++, ip++) { if (is_mmips && mm_insn_16bit(ip->halfword[0])) { insn.halfword[0] = 0; insn.halfword[1] = ip->halfword[0]; From 67c75057709a6d85c681c78b9b2f9b71191f01a2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 15:07:05 +0000 Subject: [PATCH 0109/1587] MIPS: Fix is_jump_ins() handling of 16b microMIPS instructions is_jump_ins() checks 16b instruction fields without verifying that the instruction is indeed 16b, as is done by is_ra_save_ins() & is_sp_move_ins(). Add the appropriate check. Signed-off-by: Paul Burton Fixes: 34c2f668d0f6 ("MIPS: microMIPS: Add unaligned access support.") Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Cc: # v3.10+ Patchwork: https://patchwork.linux-mips.org/patch/14531/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 9f7a19ca1d4c..e03113493580 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -242,9 +242,14 @@ static inline int is_jump_ins(union mips_instruction *ip) * * microMIPS is kind of more fun... */ - if ((ip->mm16_r5_format.opcode == mm_pool16c_op && - (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) || - ip->j_format.opcode == mm_jal32_op) + if (mm_insn_16bit(ip->halfword[1])) { + if ((ip->mm16_r5_format.opcode == mm_pool16c_op && + (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op)) + return 1; + return 0; + } + + if (ip->j_format.opcode == mm_jal32_op) return 1; if (ip->r_format.opcode != mm_pool32a_op || ip->r_format.func != mm_pool32axf_op) From bb9bc4689b9c635714fbcd5d335bad9934a7ebfc Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 15:07:06 +0000 Subject: [PATCH 0110/1587] MIPS: Calculate microMIPS ra properly when unwinding the stack get_frame_info() calculates the offset of the return address within a stack frame simply by dividing a the bottom 16 bits of the instruction, treated as a signed integer, by the size of a long. Whilst this works for MIPS32 & MIPS64 ISAs where the sw or sd instructions are used, it's incorrect for microMIPS where encodings differ. The result is that we typically completely fail to unwind the stack on microMIPS. Fix this by adjusting is_ra_save_ins() to calculate the return address offset, and take into account the various different encodings there in the same place as we consider whether an instruction is storing the ra/$31 register. With this we are now able to unwind the stack for kernels targetting the microMIPS ISA, for example we can produce: Call Trace: [<80109e1f>] show_stack+0x63/0x7c [<8011ea17>] __warn+0x9b/0xac [<8011ea45>] warn_slowpath_fmt+0x1d/0x20 [<8013fe53>] register_console+0x43/0x314 [<8067c58d>] of_setup_earlycon+0x1dd/0x1ec [<8067f63f>] early_init_dt_scan_chosen_stdout+0xe7/0xf8 [<8066c115>] do_early_param+0x75/0xac [<801302f9>] parse_args+0x1dd/0x308 [<8066c459>] parse_early_options+0x25/0x28 [<8066c48b>] parse_early_param+0x2f/0x38 [<8066e8cf>] setup_arch+0x113/0x488 [<8066c4f3>] start_kernel+0x57/0x328 ---[ end trace 0000000000000000 ]--- Whereas previously we only produced: Call Trace: [<80109e1f>] show_stack+0x63/0x7c ---[ end trace 0000000000000000 ]--- Signed-off-by: Paul Burton Fixes: 34c2f668d0f6 ("MIPS: microMIPS: Add unaligned access support.") Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Cc: # v3.10+ Patchwork: https://patchwork.linux-mips.org/patch/14532/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 83 +++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index e03113493580..801b399d4861 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -196,7 +196,7 @@ struct mips_frame_info { #define J_TARGET(pc,target) \ (((unsigned long)(pc) & 0xf0000000) | ((target) << 2)) -static inline int is_ra_save_ins(union mips_instruction *ip) +static inline int is_ra_save_ins(union mips_instruction *ip, int *poff) { #ifdef CONFIG_CPU_MICROMIPS /* @@ -209,25 +209,70 @@ static inline int is_ra_save_ins(union mips_instruction *ip) * microMIPS is way more fun... */ if (mm_insn_16bit(ip->halfword[1])) { - return (ip->mm16_r5_format.opcode == mm_swsp16_op && - ip->mm16_r5_format.rt == 31) || - (ip->mm16_m_format.opcode == mm_pool16c_op && - ip->mm16_m_format.func == mm_swm16_op); + switch (ip->mm16_r5_format.opcode) { + case mm_swsp16_op: + if (ip->mm16_r5_format.rt != 31) + return 0; + + *poff = ip->mm16_r5_format.simmediate; + *poff = (*poff << 2) / sizeof(ulong); + return 1; + + case mm_pool16c_op: + switch (ip->mm16_m_format.func) { + case mm_swm16_op: + *poff = ip->mm16_m_format.imm; + *poff += 1 + ip->mm16_m_format.rlist; + *poff = (*poff << 2) / sizeof(ulong); + return 1; + + default: + return 0; + } + + default: + return 0; + } } - else { - return (ip->mm_m_format.opcode == mm_pool32b_op && - ip->mm_m_format.rd > 9 && - ip->mm_m_format.base == 29 && - ip->mm_m_format.func == mm_swm32_func) || - (ip->i_format.opcode == mm_sw32_op && - ip->i_format.rs == 29 && - ip->i_format.rt == 31); + + switch (ip->i_format.opcode) { + case mm_sw32_op: + if (ip->i_format.rs != 29) + return 0; + if (ip->i_format.rt != 31) + return 0; + + *poff = ip->i_format.simmediate / sizeof(ulong); + return 1; + + case mm_pool32b_op: + switch (ip->mm_m_format.func) { + case mm_swm32_func: + if (ip->mm_m_format.rd < 0x10) + return 0; + if (ip->mm_m_format.base != 29) + return 0; + + *poff = ip->mm_m_format.simmediate; + *poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32); + *poff /= sizeof(ulong); + return 1; + default: + return 0; + } + + default: + return 0; } #else /* sw / sd $ra, offset($sp) */ - return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && - ip->i_format.rs == 29 && - ip->i_format.rt == 31; + if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && + ip->i_format.rs == 29 && ip->i_format.rt == 31) { + *poff = ip->i_format.simmediate / sizeof(ulong); + return 1; + } + + return 0; #endif } @@ -350,11 +395,9 @@ static int get_frame_info(struct mips_frame_info *info) } continue; } - if (info->pc_offset == -1 && is_ra_save_ins(&insn)) { - info->pc_offset = - ip->i_format.simmediate / sizeof(long); + if (info->pc_offset == -1 && + is_ra_save_ins(&insn, &info->pc_offset)) break; - } } if (info->frame_size && info->pc_offset >= 0) /* nested */ return 0; From 096a0de427ea333f56f0ee00328cff2a2731bcf1 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 15:07:07 +0000 Subject: [PATCH 0111/1587] MIPS: Handle microMIPS jumps in the same way as MIPS32/MIPS64 jumps is_jump_ins() checks for plain jump ("j") instructions since commit e7438c4b893e ("MIPS: Fix sibling call handling in get_frame_info") but that commit didn't make the same change to the microMIPS code, leaving it inconsistent with the MIPS32/MIPS64 code. Handle the microMIPS encoding of the jump instruction too such that it behaves consistently. Signed-off-by: Paul Burton Fixes: e7438c4b893e ("MIPS: Fix sibling call handling in get_frame_info") Cc: Tony Wu Cc: linux-mips@linux-mips.org Cc: # v3.10+ Patchwork: https://patchwork.linux-mips.org/patch/14533/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 801b399d4861..efa1df52c616 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -294,6 +294,8 @@ static inline int is_jump_ins(union mips_instruction *ip) return 0; } + if (ip->j_format.opcode == mm_j32_op) + return 1; if (ip->j_format.opcode == mm_jal32_op) return 1; if (ip->r_format.opcode != mm_pool32a_op || From 44079d3509aee89c58f3e4fd929fa53ab2299019 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 10 Nov 2016 10:02:13 +0000 Subject: [PATCH 0112/1587] MIPS: Use Makefile.postlink to insert relocations into vmlinux When relocatable support for MIPS was merged, there was no support for an architecture to add a postlink step for vmlinux. This meant that only invoking a target within the boot directory, such as uImage, caused the relocations to be inserted into vmlinux. Building just the vmlinux target would result in a relocatable kernel with no relocation information present. Commit fbe6e37dab97 ("kbuild: add arch specific post-link Makefile") recified this situation, so MIPS can now define a postlink step to add relocation information into vmlinux, and remove the additional steps tacked onto boot targets. Signed-off-by: Matt Redfearn Tested-by: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14554/ Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 12 ------------ arch/mips/Makefile.postlink | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 arch/mips/Makefile.postlink diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 0f6e95cba43c..06d79586368e 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -330,10 +330,6 @@ rom.bin rom.sw: vmlinux $(bootvars-y) $@ endif -CMD_RELOCS = arch/mips/boot/tools/relocs -quiet_cmd_relocs = RELOCS $< - cmd_relocs = $(CMD_RELOCS) $< - # # Some machines like the Indy need 32-bit ELF binaries for booting purposes. # Other need ECOFF, so we build a 32-bit ELF binary for them which we then @@ -342,11 +338,6 @@ quiet_cmd_relocs = RELOCS $< quiet_cmd_32 = OBJCOPY $@ cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ vmlinux.32: vmlinux -ifeq ($(CONFIG_RELOCATABLE)$(CONFIG_64BIT),yy) -# Currently, objcopy fails to handle the relocations in the elf64 -# So the relocs tool must be run here to remove them first - $(call cmd,relocs) -endif $(call cmd,32) # @@ -362,9 +353,6 @@ all: $(all-y) # boot $(boot-y): $(vmlinux-32) FORCE -ifeq ($(CONFIG_RELOCATABLE)$(CONFIG_32BIT),yy) - $(call cmd,relocs) -endif $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) \ $(bootvars-y) arch/mips/boot/$@ diff --git a/arch/mips/Makefile.postlink b/arch/mips/Makefile.postlink new file mode 100644 index 000000000000..b0ddf0701a31 --- /dev/null +++ b/arch/mips/Makefile.postlink @@ -0,0 +1,35 @@ +# =========================================================================== +# Post-link MIPS pass +# =========================================================================== +# +# 1. Insert relocations into vmlinux + +PHONY := __archpost +__archpost: + +include include/config/auto.conf +include scripts/Kbuild.include + +CMD_RELOCS = arch/mips/boot/tools/relocs +quiet_cmd_relocs = RELOCS $@ + cmd_relocs = $(CMD_RELOCS) $@ + +# `@true` prevents complaint when there is nothing to be done + +vmlinux: FORCE + @true +ifeq ($(CONFIG_RELOCATABLE),y) + $(call if_changed,relocs) +endif + +%.ko: FORCE + @true + +clean: + @true + +PHONY += FORCE clean + +FORCE: + +.PHONY: $(PHONY) From 225844c59f12e1bad446ef3c2584915aae32c04a Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:28:12 +0000 Subject: [PATCH 0113/1587] MIPS: Remove unused HIGHMEM_DEBUG macro We have a HIGHMEM_DEBUG macro defined in asm/highmem.h with a comment stating that it should be removed for production, and no users... Kill it. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14523/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/highmem.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 64f2500d891b..d34536e7653f 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -25,9 +25,6 @@ #include #include -/* undef for production */ -#define HIGHMEM_DEBUG 1 - /* declarations for highmem.c */ extern unsigned long highstart_pfn, highend_pfn; From 9799270affc53414da96e77e454a5616b39cdab0 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:30:41 +0000 Subject: [PATCH 0114/1587] MIPS: Netlogic: Exclude netlogic,xlp-pic code from XLR builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code in arch/mips/netlogic/common/irq.c which handles the XLP PIC fails to build in XLR configurations due to cpu_is_xlp9xx not being defined, leading to the following build failure: arch/mips/netlogic/common/irq.c: In function ‘xlp_of_pic_init’: arch/mips/netlogic/common/irq.c:298:2: error: implicit declaration of function ‘cpu_is_xlp9xx’ [-Werror=implicit-function-declaration] if (cpu_is_xlp9xx()) { ^ Although the code was conditional upon CONFIG_OF which is indirectly selected by CONFIG_NLM_XLP_BOARD but not CONFIG_NLM_XLR_BOARD, the failing XLR with CONFIG_OF configuration can be configured manually or by randconfig. Fix the build failure by making the affected XLP PIC code conditional upon CONFIG_CPU_XLP which is used to guard the inclusion of asm/netlogic/xlp-hal/xlp.h that provides the required cpu_is_xlp9xx function. [ralf@linux-mips.org: Fixed up as per Jayachandran's suggestion.] Signed-off-by: Paul Burton Cc: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14524/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/common/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 3660dc67d544..f4961bc9a61d 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -275,7 +275,7 @@ asmlinkage void plat_irq_dispatch(void) do_IRQ(nlm_irq_to_xirq(node, i)); } -#ifdef CONFIG_OF +#ifdef CONFIG_CPU_XLP static const struct irq_domain_ops xlp_pic_irq_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; @@ -348,7 +348,7 @@ void __init arch_init_irq(void) #if defined(CONFIG_CPU_XLR) nlm_setup_fmn_irq(); #endif -#if defined(CONFIG_OF) +#ifdef CONFIG_CPU_XLP of_irq_init(xlp_pic_irq_ids); #endif } From a00eeede507c975087b7b8df8cf2c9f88ba285de Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Fri, 4 Nov 2016 09:28:56 +0000 Subject: [PATCH 0115/1587] MIPS: SMP: Use a completion event to signal CPU up If a secondary CPU failed to start, for any reason, the CPU requesting the secondary to start would get stuck in the loop waiting for the secondary to be present in the cpu_callin_map. Rather than that, use a completion event to signal that the secondary CPU has started and is waiting to synchronise counters. Since the CPU presence will no longer be marked in cpu_callin_map, remove the redundant test from arch_cpu_idle_dead(). Signed-off-by: Matt Redfearn Cc: Maciej W. Rozycki Cc: Jiri Slaby Cc: Paul Gortmaker Cc: Chris Metcalf Cc: Thomas Gleixner Cc: Qais Yousef Cc: James Hogan Cc: Paul Burton Cc: Marcin Nowakowski Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14502/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 4 +--- arch/mips/kernel/smp.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index efa1df52c616..3da0161bdf84 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -50,9 +50,7 @@ #ifdef CONFIG_HOTPLUG_CPU void arch_cpu_idle_dead(void) { - /* What the heck is this check doing ? */ - if (!cpumask_test_cpu(smp_processor_id(), &cpu_callin_map)) - play_dead(); + play_dead(); } #endif diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 7ebb1918e2ac..03daf9008124 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -68,6 +68,8 @@ EXPORT_SYMBOL(cpu_sibling_map); cpumask_t cpu_core_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_core_map); +static DECLARE_COMPLETION(cpu_running); + /* * A logcal cpu mask containing only one VPE per core to * reduce the number of IPIs on large MT systems. @@ -369,7 +371,7 @@ asmlinkage void start_secondary(void) cpumask_set_cpu(cpu, &cpu_coherent_mask); notify_cpu_starting(cpu); - cpumask_set_cpu(cpu, &cpu_callin_map); + complete(&cpu_running); synchronise_count_slave(cpu); set_cpu_online(cpu, true); @@ -430,7 +432,6 @@ void smp_prepare_boot_cpu(void) { set_cpu_possible(0, true); set_cpu_online(0, true); - cpumask_set_cpu(0, &cpu_callin_map); } int __cpu_up(unsigned int cpu, struct task_struct *tidle) @@ -438,11 +439,13 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) mp_ops->boot_secondary(cpu, tidle); /* - * Trust is futile. We should really have timeouts ... + * We must check for timeout here, as the CPU will not be marked + * online until the counters are synchronised. */ - while (!cpumask_test_cpu(cpu, &cpu_callin_map)) { - udelay(100); - schedule(); + if (!wait_for_completion_timeout(&cpu_running, + msecs_to_jiffies(1000))) { + pr_crit("CPU%u: failed to start\n", cpu); + return -EIO; } synchronise_count_master(cpu); From 5892d6a60341d50e1765a86fba0976c747f4fb19 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Fri, 4 Nov 2016 09:28:57 +0000 Subject: [PATCH 0116/1587] MIPS: SMP: Remove cpu_callin_map The previous commit made cpu_callin_map redundant, since it is no longer used to signal secondary CPUs starting, or going offline. Remove it now. Signed-off-by: Matt Redfearn Cc: Sebastian Andrzej Siewior Cc: Qais Yousef Cc: Masahiro Yamada Cc: Huacai Chen Cc: Kevin Cernekee Cc: Thomas Gleixner Cc: Andrew Morton Cc: James Hogan Cc: Paul Burton Cc: Florian Fainelli Cc: Anna-Maria Gleixner Cc: Adam Buchbinder Cc: Yang Shi Cc: David Daney Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14503/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/smp.c | 1 - arch/mips/include/asm/smp.h | 2 -- arch/mips/kernel/smp-bmips.c | 1 - arch/mips/kernel/smp-cps.c | 1 - arch/mips/kernel/smp.c | 2 -- arch/mips/loongson64/loongson-3/smp.c | 1 - 6 files changed, 8 deletions(-) diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 889c3f49dbc0..a3d731479141 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -290,7 +290,6 @@ static int octeon_cpu_disable(void) set_cpu_online(cpu, false); calculate_cpu_foreign_map(); - cpumask_clear_cpu(cpu, &cpu_callin_map); octeon_fixup_irqs(); __flush_cache_all(); diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index 060f23ff1817..f8c5faa93584 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -46,8 +46,6 @@ extern int __cpu_logical_map[NR_CPUS]; #define SMP_DUMP 0x8 #define SMP_ASK_C0COUNT 0x10 -extern cpumask_t cpu_callin_map; - /* Mask of CPUs which are currently definitely operating coherently */ extern cpumask_t cpu_coherent_mask; diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 6d0f1321e084..f6700dc2fb09 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -364,7 +364,6 @@ static int bmips_cpu_disable(void) set_cpu_online(cpu, false); calculate_cpu_foreign_map(); - cpumask_clear_cpu(cpu, &cpu_callin_map); clear_c0_status(IE_IRQ5); local_flush_tlb_all(); diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 6183ad84cc73..44339b470ef4 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -399,7 +399,6 @@ static int cps_cpu_disable(void) smp_mb__after_atomic(); set_cpu_online(cpu, false); calculate_cpu_foreign_map(); - cpumask_clear_cpu(cpu, &cpu_callin_map); return 0; } diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 03daf9008124..0a831f63b0ec 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -48,8 +48,6 @@ #include #include -cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ - int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ EXPORT_SYMBOL(__cpu_number_map); diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index 99aab9f85904..cfcf240cedbe 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -418,7 +418,6 @@ static int loongson3_cpu_disable(void) set_cpu_online(cpu, false); calculate_cpu_foreign_map(); - cpumask_clear_cpu(cpu, &cpu_callin_map); local_irq_save(flags); fixup_irqs(); local_irq_restore(flags); From 5b0093f3a4acc7f393f102e7e064f70efc3375b9 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Fri, 4 Nov 2016 09:28:58 +0000 Subject: [PATCH 0117/1587] MIPS: SMP-CPS: Don't BUG if a CPU fails to start If there is no online CPU within a core which could receive the IPI to start another VP in that core, a BUG() is triggered. Instead print a warning and gracefully handle the failure such that the system remains usable, albeit without the requested secondary CPU. Signed-off-by: Matt Redfearn Cc: Masahiro Yamada Cc: James Hogan Cc: Paul Burton Cc: Qais Yousef Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14504/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp-cps.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 44339b470ef4..a2544c2394e4 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -326,7 +326,11 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) if (cpu_online(remote)) break; } - BUG_ON(remote >= NR_CPUS); + if (remote >= NR_CPUS) { + pr_crit("No online CPU in core %u to start CPU%d\n", + core, cpu); + goto out; + } err = smp_call_function_single(remote, remote_vpe_boot, NULL, 1); From 20d6f0c3e2832e98400cacf986aee9b6eeca65df Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 30 Oct 2016 09:25:46 +0100 Subject: [PATCH 0118/1587] MIPS: ath79: Fix error handling 'clk_register_fixed_rate()' returns an error pointer in case of error, not NULL. So test it with IS_ERR. Signed-off-by: Christophe JAILLET Acked-by: Aban Bedel Cc: antonynpavlov@gmail.com Cc: hackpascal@gmail.com Cc: amitoj1606@gmail.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: kernel-janitors@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14464/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c index cc3a1e33a600..c1102cffe37d 100644 --- a/arch/mips/ath79/clock.c +++ b/arch/mips/ath79/clock.c @@ -45,7 +45,7 @@ static struct clk *__init ath79_add_sys_clkdev( int err; clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate); - if (!clk) + if (IS_ERR(clk)) panic("failed to allocate %s clock structure", id); err = clk_register_clkdev(clk, id, NULL); From 35b258dc24f07d061513d5edba723faf6bf8b387 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 22 Nov 2016 17:52:38 +0000 Subject: [PATCH 0119/1587] MIPS: xilfpga: Use irqchip instead of the legacy way This prepares the code to use the Xilinx Interrupt Controller driver in drivers/irqchip/irq-xilinx-intc.c Signed-off-by: Zubair Lutfullah Kakakhel Cc: Zubair.Kakakhel@imgtec.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14591/ Signed-off-by: Ralf Baechle --- arch/mips/xilfpga/intc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/mips/xilfpga/intc.c b/arch/mips/xilfpga/intc.c index c4d1a716b347..a127cca3ae8c 100644 --- a/arch/mips/xilfpga/intc.c +++ b/arch/mips/xilfpga/intc.c @@ -11,15 +11,12 @@ #include #include +#include #include -static struct of_device_id of_irq_ids[] __initdata = { - { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, - {}, -}; void __init arch_init_irq(void) { - of_irq_init(of_irq_ids); + irqchip_init(); } From 79a93295339c1983efcecb466e17edd786a9c556 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 22 Nov 2016 17:52:39 +0000 Subject: [PATCH 0120/1587] MIPS: xilfpga: Use Xilinx Interrupt Controller IRQs from peripherals such as i2c/uart/ethernet come via the AXI Interrupt controller. Select it in Kconfig for xilfpga and add the DT node Signed-off-by: Zubair Lutfullah Kakakhel Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14592/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7cb4b0e5f49a..af4eed3136f5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -479,6 +479,7 @@ config MACH_XILFPGA select SYS_SUPPORTS_ZBOOT_UART16550 select USE_OF select USE_GENERIC_EARLY_PRINTK_8250 + select XILINX_INTC help This enables support for the IMG University Program MIPSfpga platform. diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts index 48d21127c3f3..8db660b06ac9 100644 --- a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts +++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts @@ -17,6 +17,18 @@ compatible = "mti,cpu-interrupt-controller"; }; + axi_intc: interrupt-controller@10200000 { + #interrupt-cells = <1>; + compatible = "xlnx,xps-intc-1.00.a"; + interrupt-controller; + reg = <0x10200000 0x10000>; + xlnx,kind-of-intr = <0x0>; + xlnx,num-intr-inputs = <0x6>; + + interrupt-parent = <&cpuintc>; + interrupts = <6>; + }; + axi_gpio: gpio@10600000 { #gpio-cells = <1>; compatible = "xlnx,xps-gpio-1.00.a"; From 1e73f967474efc793a9d6a5c27f35e9b619b2db9 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 22 Nov 2016 17:52:40 +0000 Subject: [PATCH 0121/1587] MIPS: xilfpga: Update DT node and specify uart irq Update the DT node with the UART irq Signed-off-by: Zubair Lutfullah Kakakhel Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14593/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts index 8db660b06ac9..d285c8d10bce 100644 --- a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts +++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts @@ -50,6 +50,9 @@ reg-offset = <0x1000>; clocks = <&ext>; + + interrupt-parent = <&axi_intc>; + interrupts = <0>; }; }; From da621d5022886311d6634b8995c9b9fc9d9b7d36 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 22 Nov 2016 17:52:41 +0000 Subject: [PATCH 0122/1587] MIPS: xilfpga: Add DT node for AXI I2C The xilfpga platform has an AXI I2C Bus master with a temperature sensor connected to it. Add the device tree node to use them. Signed-off-by: Zubair Lutfullah Kakakhel Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14594/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts index d285c8d10bce..f5ebab85d42e 100644 --- a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts +++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts @@ -54,6 +54,28 @@ interrupt-parent = <&axi_intc>; interrupts = <0>; }; + + axi_i2c: i2c@10A00000 { + compatible = "xlnx,xps-iic-2.00.a"; + interrupt-parent = <&axi_intc>; + interrupts = <4>; + reg = < 0x10A00000 0x10000 >; + clocks = <&ext>; + xlnx,clk-freq = <0x5f5e100>; + xlnx,family = "Artix7"; + xlnx,gpo-width = <0x1>; + xlnx,iic-freq = <0x186a0>; + xlnx,scl-inertial-delay = <0x0>; + xlnx,sda-inertial-delay = <0x0>; + xlnx,ten-bit-adr = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + ad7420@4B { + compatible = "adi,adt7420"; + reg = <0x4B>; + }; + } ; }; &ext { From beb6e9b368dc59c55d5d4cf9a1e5a613521f1cfe Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 22 Nov 2016 17:52:42 +0000 Subject: [PATCH 0123/1587] MIPS: xilfpga: Add DT node for AXI emaclite The xilfpga platform has a Xilinx AXI emaclite block. Add the DT node to use it. Signed-off-by: Zubair Lutfullah Kakakhel Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14596/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts index f5ebab85d42e..09a62f2e2f8f 100644 --- a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts +++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts @@ -42,6 +42,32 @@ xlnx,tri-default = <0xffffffff>; } ; + axi_ethernetlite: ethernet@10e00000 { + compatible = "xlnx,xps-ethernetlite-3.00.a"; + device_type = "network"; + interrupt-parent = <&axi_intc>; + interrupts = <1>; + phy-handle = <&phy0>; + reg = <0x10e00000 0x10000>; + xlnx,duplex = <0x1>; + xlnx,include-global-buffers = <0x1>; + xlnx,include-internal-loopback = <0x0>; + xlnx,include-mdio = <0x1>; + xlnx,instance = "axi_ethernetlite_inst"; + xlnx,rx-ping-pong = <0x1>; + xlnx,s-axi-id-width = <0x1>; + xlnx,tx-ping-pong = <0x1>; + xlnx,use-internal = <0x0>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@1 { + device_type = "ethernet-phy"; + reg = <1>; + }; + }; + }; + axi_uart16550: serial@10400000 { compatible = "ns16550a"; reg = <0x10400000 0x10000>; From 60067341105d9795f2cf5bd8a19adee34824f1b1 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 22 Nov 2016 17:52:43 +0000 Subject: [PATCH 0124/1587] MIPS: xilfpga: Update defconfig Update defconfig to enable emaclite, i2c and temp sensor on the xilfpga platform Signed-off-by: Zubair Lutfullah Kakakhel Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14595/ Signed-off-by: Ralf Baechle --- arch/mips/configs/xilfpga_defconfig | 37 ++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/mips/configs/xilfpga_defconfig b/arch/mips/configs/xilfpga_defconfig index ed1dce348320..829c637be3fc 100644 --- a/arch/mips/configs/xilfpga_defconfig +++ b/arch/mips/configs/xilfpga_defconfig @@ -7,6 +7,12 @@ CONFIG_EMBEDDED=y CONFIG_SLAB=y # CONFIG_BLOCK is not set # CONFIG_SUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set # CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y @@ -14,6 +20,30 @@ CONFIG_DEVTMPFS_MOUNT=y # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_FW_LOADER is not set # CONFIG_ALLOW_DEV_COREDUMP is not set +CONFIG_NETDEVICES=y +# CONFIG_NET_CORE is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_XILINX_EMACLITE=y +CONFIG_SMSC_PHY=y +# CONFIG_WLAN is not set # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -25,13 +55,18 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_XILINX=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_XILINX=y -# CONFIG_HWMON is not set +CONFIG_SENSORS_ADT7410=y # CONFIG_USB_SUPPORT is not set # CONFIG_MIPS_PLATFORM_DEVICES is not set # CONFIG_IOMMU_SUPPORT is not set # CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_TMPFS=y # CONFIG_MISC_FILESYSTEMS is not set CONFIG_PANIC_ON_OOPS=y # CONFIG_SCHED_DEBUG is not set From 51ad4ace97ed5a4e96e60684281066b758e1de8b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 31 Oct 2016 14:17:36 -0700 Subject: [PATCH 0125/1587] MIPS: BMIPS: Migrate interrupts during bmips_cpu_disable While we properly disabled the per-CPU timer interrupt, we also need to make sure that all interrupts that can possibly have this CPU in their smp_affinity mask also have a chance to see this interrupt migrated to a CPU not being taken offline. [ralf@linux-mips.org: Fix merge conflict.] Fixes: 230b6ff57552 ("MIPS: BMIPS: Mask off timer IRQs when hot-unplugging a CPU") Signed-off-by: Florian Fainelli Cc: cernekee@gmail.com Cc: jaedon.shin@gmail.com Cc: justinpopo6@gmail.com Cc: tglx@linutronix.de Cc: marc.zyngier@arm.com Cc: jason@lakedaemon.net Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14488/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp-bmips.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index f6700dc2fb09..16e37a28f876 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -364,6 +364,7 @@ static int bmips_cpu_disable(void) set_cpu_online(cpu, false); calculate_cpu_foreign_map(); + irq_cpu_offline(); clear_c0_status(IE_IRQ5); local_flush_tlb_all(); From c11621256c6f020944573daf3ea5963f37978abd Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Tue, 9 Aug 2016 16:23:11 +0800 Subject: [PATCH 0126/1587] MIPS: Loongson1C: Remove ARCH_WANT_OPTIONAL_GPIOLIB This patch removes ARCH_WANT_OPTIONAL_GPIOLIB due to upstream changes. Signed-off-by: Kelvin Cheung Acked-by: Linus Walleij Cc: Yang Ling Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13855/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index af4eed3136f5..40908304d1ef 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1430,7 +1430,6 @@ config CPU_LOONGSON1C bool "Loongson 1C" depends on SYS_HAS_CPU_LOONGSON1C select CPU_LOONGSON1 - select ARCH_WANT_OPTIONAL_GPIOLIB select LEDS_GPIO_REGISTER help The Loongson 1C is a 32-bit SoC, which implements the MIPS32 From 1d79bf0e908202e3141c37d0ad89020ea93ad38a Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Tue, 9 Aug 2016 18:52:59 +0800 Subject: [PATCH 0127/1587] MIPS: Loongson1B: Modify DEFAULT_MEMSIZE This patch changes DEFAULT_MEMSIZE to 64MB which is the memory size of latest EVB. Signed-off-by: Kelvin Cheung Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13856/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-loongson32/loongson1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/mach-loongson32/loongson1.h b/arch/mips/include/asm/mach-loongson32/loongson1.h index 3584c40caf79..ec7efd0de744 100644 --- a/arch/mips/include/asm/mach-loongson32/loongson1.h +++ b/arch/mips/include/asm/mach-loongson32/loongson1.h @@ -13,7 +13,7 @@ #define __ASM_MACH_LOONGSON32_LOONGSON1_H #if defined(CONFIG_LOONGSON1_LS1B) -#define DEFAULT_MEMSIZE 256 /* If no memsize provided */ +#define DEFAULT_MEMSIZE 64 /* If no memsize provided */ #elif defined(CONFIG_LOONGSON1_LS1C) #define DEFAULT_MEMSIZE 32 #endif From d65e5677ad5b3a49c43f60ec07644dc1f87bbd2e Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Thu, 25 Aug 2016 10:37:38 -0700 Subject: [PATCH 0128/1587] MIPS: R2-on-R6 MULTU/MADDU/MSUBU emulation bugfix MIPS instructions MULTU, MADDU and MSUBU emulation requires registers HI/LO to be converted to signed 32bits before 64bit sign extension on MIPS64. Bug was found on running MIPS32 R2 test application on MIPS64 R6 kernel. Fixes: b0a668fb2038 ("MIPS: kernel: mips-r2-to-r6-emul: Add R2 emulator for MIPS R6") Signed-off-by: Leonid Yegoshin Reported-by: Nikola.Veljkovic@imgtec.com Cc: paul.burton@imgtec.com Cc: yamada.masahiro@socionext.com Cc: akpm@linux-foundation.org Cc: andrea.gelmini@gelma.net Cc: macro@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14043/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-r2-to-r6-emul.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index ef2ca28a028b..d8f1cf1ec370 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -433,8 +433,8 @@ static int multu_func(struct pt_regs *regs, u32 ir) rs = regs->regs[MIPSInst_RS(ir)]; res = (u64)rt * (u64)rs; rt = res; - regs->lo = (s64)rt; - regs->hi = (s64)(res >> 32); + regs->lo = (s64)(s32)rt; + regs->hi = (s64)(s32)(res >> 32); MIPS_R2_STATS(muls); @@ -670,9 +670,9 @@ static int maddu_func(struct pt_regs *regs, u32 ir) res += ((((s64)rt) << 32) | (u32)rs); rt = res; - regs->lo = (s64)rt; + regs->lo = (s64)(s32)rt; rs = res >> 32; - regs->hi = (s64)rs; + regs->hi = (s64)(s32)rs; MIPS_R2_STATS(dsps); @@ -728,9 +728,9 @@ static int msubu_func(struct pt_regs *regs, u32 ir) res = ((((s64)rt) << 32) | (u32)rs) - res; rt = res; - regs->lo = (s64)rt; + regs->lo = (s64)(s32)rt; rs = res >> 32; - regs->hi = (s64)rs; + regs->hi = (s64)(s32)rs; MIPS_R2_STATS(dsps); From 35e6de38858f59b6b65dcfeaf700b5d06fc2b93d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 17 Oct 2016 16:01:07 +0100 Subject: [PATCH 0129/1587] MIPS: traps: Ensure L1 & L2 ECC checking match for CM3 systems On systems with CM3, we must ensure that the L1 & L2 ECC enables are set to the same value. This is presumed by the hardware & cache corruption can occur when it is not the case. Support enabling & disabling the L2 ECC checking on CM3 systems where this is controlled via a GCR, and ensure that it matches the state of L1 ECC checking. Remove I6400 from the switch statement it will no longer hit, and which was incorrect since the L2 ECC enable bit isn't in the CP0 ErrCtl register. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14413/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 7 ++++ arch/mips/kernel/traps.c | 63 +++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 2e4180797b21..cfdbab015769 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -187,6 +187,7 @@ BUILD_CM_R_(config, MIPS_CM_GCB_OFS + 0x00) BUILD_CM_RW(base, MIPS_CM_GCB_OFS + 0x08) BUILD_CM_RW(access, MIPS_CM_GCB_OFS + 0x20) BUILD_CM_R_(rev, MIPS_CM_GCB_OFS + 0x30) +BUILD_CM_RW(err_control, MIPS_CM_GCB_OFS + 0x38) BUILD_CM_RW(error_mask, MIPS_CM_GCB_OFS + 0x40) BUILD_CM_RW(error_cause, MIPS_CM_GCB_OFS + 0x48) BUILD_CM_RW(error_addr, MIPS_CM_GCB_OFS + 0x50) @@ -266,6 +267,12 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_REV_CM2_5 CM_ENCODE_REV(7, 0) #define CM_REV_CM3 CM_ENCODE_REV(8, 0) +/* GCR_ERR_CONTROL register fields */ +#define CM_GCR_ERR_CONTROL_L2_ECC_EN_SHF 1 +#define CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK (_ULCAST_(0x1) << 1) +#define CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_SHF 0 +#define CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_MSK (_ULCAST_(0x1) << 0) + /* GCR_ERROR_CAUSE register fields */ #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27 #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 6c7f9d7e92b3..9ea6959cd5bb 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -1644,6 +1645,65 @@ __setup("nol2par", nol2parity); */ static inline void parity_protection_init(void) { +#define ERRCTL_PE 0x80000000 +#define ERRCTL_L2P 0x00800000 + + if (mips_cm_revision() >= CM_REV_CM3) { + ulong gcr_ectl, cp0_ectl; + + /* + * With CM3 systems we need to ensure that the L1 & L2 + * parity enables are set to the same value, since this + * is presumed by the hardware engineers. + * + * If the user disabled either of L1 or L2 ECC checking, + * disable both. + */ + l1parity &= l2parity; + l2parity &= l1parity; + + /* Probe L1 ECC support */ + cp0_ectl = read_c0_ecc(); + write_c0_ecc(cp0_ectl | ERRCTL_PE); + back_to_back_c0_hazard(); + cp0_ectl = read_c0_ecc(); + + /* Probe L2 ECC support */ + gcr_ectl = read_gcr_err_control(); + + if (!(gcr_ectl & CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_MSK) || + !(cp0_ectl & ERRCTL_PE)) { + /* + * One of L1 or L2 ECC checking isn't supported, + * so we cannot enable either. + */ + l1parity = l2parity = 0; + } + + /* Configure L1 ECC checking */ + if (l1parity) + cp0_ectl |= ERRCTL_PE; + else + cp0_ectl &= ~ERRCTL_PE; + write_c0_ecc(cp0_ectl); + back_to_back_c0_hazard(); + WARN_ON(!!(read_c0_ecc() & ERRCTL_PE) != l1parity); + + /* Configure L2 ECC checking */ + if (l2parity) + gcr_ectl |= CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK; + else + gcr_ectl &= ~CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK; + write_gcr_err_control(gcr_ectl); + gcr_ectl = read_gcr_err_control(); + gcr_ectl &= CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK; + WARN_ON(!!gcr_ectl != l2parity); + + pr_info("Cache parity protection %sabled\n", + l1parity ? "en" : "dis"); + return; + } + switch (current_cpu_type()) { case CPU_24K: case CPU_34K: @@ -1654,11 +1714,8 @@ static inline void parity_protection_init(void) case CPU_PROAPTIV: case CPU_P5600: case CPU_QEMU_GENERIC: - case CPU_I6400: case CPU_P6600: { -#define ERRCTL_PE 0x80000000 -#define ERRCTL_L2P 0x00800000 unsigned long errctl; unsigned int l1parity_present, l2parity_present; From d774a5896e7dd2add2e352ab328ec8d41f7cb68b Mon Sep 17 00:00:00 2001 From: Rahul Bedarkar Date: Fri, 14 Oct 2016 11:25:54 +0530 Subject: [PATCH 0130/1587] MIPS: DTS: Add base device tree for Pistachio SoC Add support for the base Device Tree for Imagination Technologies' Pistachio SoC. This commit supports the following peripherals: * Clocks * Pinctrl and GPIO * UART * SPI * I2C * PWM * ADC * Watchdog * Ethernet * MMC * DMA engine * Crypto * I2S * SPDIF * Internal DAC * Timer * USB * IR * Interrupt Controller Signed-off-by: Rahul Bedarkar Acked-by: James Hartley Cc: Rob Herring Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14393/ Signed-off-by: Ralf Baechle --- MAINTAINERS | 2 +- arch/mips/boot/dts/img/pistachio.dtsi | 924 ++++++++++++++++++++++++++ 2 files changed, 925 insertions(+), 1 deletion(-) create mode 100644 arch/mips/boot/dts/img/pistachio.dtsi diff --git a/MAINTAINERS b/MAINTAINERS index cfff2c9e3d94..eaa1586d137a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9762,7 +9762,7 @@ L: linux-mips@linux-mips.org S: Maintained F: arch/mips/pistachio/ F: arch/mips/include/asm/mach-pistachio/ -F: arch/mips/boot/dts/pistachio/ +F: arch/mips/boot/dts/img/pistachio* F: arch/mips/configs/pistachio*_defconfig PKTCDVD DRIVER diff --git a/arch/mips/boot/dts/img/pistachio.dtsi b/arch/mips/boot/dts/img/pistachio.dtsi new file mode 100644 index 000000000000..57809f6a5864 --- /dev/null +++ b/arch/mips/boot/dts/img/pistachio.dtsi @@ -0,0 +1,924 @@ +/* + * Copyright (C) 2015, 2016 Imagination Technologies Ltd. + * Copyright (C) 2015 Google, Inc. + * + * 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 + +/ { + compatible = "img,pistachio"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "mti,interaptiv"; + reg = <0>; + clocks = <&clk_core CLK_MIPS_PLL>; + clock-names = "cpu"; + clock-latency = <1000>; + operating-points = < + /* kHz uV(dummy) */ + 546000 1150000 + 520000 1100000 + 494000 1000000 + 468000 950000 + 442000 900000 + 416000 800000 + >; + }; + }; + + i2c0: i2c@18100000 { + compatible = "img,scb-i2c"; + reg = <0x18100000 0x200>; + interrupts = ; + clocks = <&clk_periph PERIPH_CLK_I2C0>, + <&cr_periph SYS_CLK_I2C0>; + clock-names = "scb", "sys"; + assigned-clocks = <&clk_periph PERIPH_CLK_I2C0_PRE_DIV>, + <&clk_periph PERIPH_CLK_I2C0_DIV>; + assigned-clock-rates = <100000000>, <33333334>; + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c1: i2c@18100200 { + compatible = "img,scb-i2c"; + reg = <0x18100200 0x200>; + interrupts = ; + clocks = <&clk_periph PERIPH_CLK_I2C1>, + <&cr_periph SYS_CLK_I2C1>; + clock-names = "scb", "sys"; + assigned-clocks = <&clk_periph PERIPH_CLK_I2C1_PRE_DIV>, + <&clk_periph PERIPH_CLK_I2C1_DIV>; + assigned-clock-rates = <100000000>, <33333334>; + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@18100400 { + compatible = "img,scb-i2c"; + reg = <0x18100400 0x200>; + interrupts = ; + clocks = <&clk_periph PERIPH_CLK_I2C2>, + <&cr_periph SYS_CLK_I2C2>; + clock-names = "scb", "sys"; + assigned-clocks = <&clk_periph PERIPH_CLK_I2C2_PRE_DIV>, + <&clk_periph PERIPH_CLK_I2C2_DIV>; + assigned-clock-rates = <100000000>, <33333334>; + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c3: i2c@18100600 { + compatible = "img,scb-i2c"; + reg = <0x18100600 0x200>; + interrupts = ; + clocks = <&clk_periph PERIPH_CLK_I2C3>, + <&cr_periph SYS_CLK_I2C3>; + clock-names = "scb", "sys"; + assigned-clocks = <&clk_periph PERIPH_CLK_I2C3_PRE_DIV>, + <&clk_periph PERIPH_CLK_I2C3_DIV>; + assigned-clock-rates = <100000000>, <33333334>; + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + i2s_in: i2s-in@18100800 { + compatible = "img,i2s-in"; + reg = <0x18100800 0x200>; + interrupts = ; + dmas = <&mdc 30 0xffffffff 0>; + dma-names = "rx"; + clocks = <&cr_periph SYS_CLK_I2S_IN>; + clock-names = "sys"; + img,i2s-channels = <6>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s_in_pins>; + status = "disabled"; + + #sound-dai-cells = <0>; + }; + + i2s_out: i2s-out@18100a00 { + compatible = "img,i2s-out"; + reg = <0x18100a00 0x200>; + interrupts = ; + dmas = <&mdc 23 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_I2S_OUT>, + <&clk_core CLK_I2S>; + clock-names = "sys", "ref"; + assigned-clocks = <&clk_core CLK_I2S_DIV>; + assigned-clock-rates = <12288000>; + img,i2s-channels = <6>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s_out_pins>; + status = "disabled"; + resets = <&pistachio_reset PISTACHIO_RESET_I2S_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; + }; + + parallel_out: parallel-audio-out@18100c00 { + compatible = "img,parallel-out"; + reg = <0x18100c00 0x100>; + interrupts = ; + dmas = <&mdc 16 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_PAUD_OUT>, + <&clk_core CLK_AUDIO_DAC>; + clock-names = "sys", "ref"; + assigned-clocks = <&clk_core CLK_AUDIO_DAC_DIV>; + assigned-clock-rates = <12288000>; + status = "disabled"; + resets = <&pistachio_reset PISTACHIO_RESET_PRL_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; + }; + + spdif_out: spdif-out@18100d00 { + compatible = "img,spdif-out"; + reg = <0x18100d00 0x100>; + interrupts = ; + dmas = <&mdc 14 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_SPDIF_OUT>, + <&clk_core CLK_SPDIF>; + clock-names = "sys", "ref"; + assigned-clocks = <&clk_core CLK_SPDIF_DIV>; + assigned-clock-rates = <12288000>; + pinctrl-names = "default"; + pinctrl-0 = <&spdif_out_pin>; + status = "disabled"; + resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; + }; + + spdif_in: spdif-in@18100e00 { + compatible = "img,spdif-in"; + reg = <0x18100e00 0x100>; + interrupts = ; + dmas = <&mdc 15 0xffffffff 0>; + dma-names = "rx"; + clocks = <&cr_periph SYS_CLK_SPDIF_IN>; + clock-names = "sys"; + pinctrl-names = "default"; + pinctrl-0 = <&spdif_in_pin>; + status = "disabled"; + + #sound-dai-cells = <0>; + }; + + internal_dac: internal-dac { + compatible = "img,pistachio-internal-dac"; + img,cr-top = <&cr_top>; + img,voltage-select = <1>; + + #sound-dai-cells = <0>; + }; + + spfi0: spi@18100f00 { + compatible = "img,spfi"; + reg = <0x18100f00 0x100>; + interrupts = ; + clocks = <&clk_core CLK_SPI0>, <&cr_periph SYS_CLK_SPI0_MASTER>; + clock-names = "sys", "spfi"; + dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>; + dma-names = "rx", "tx"; + spfi-max-frequency = <50000000>; + status = "disabled"; + + #address-cells = <1>; + #size-cells = <0>; + }; + + spfi1: spi@18101000 { + compatible = "img,spfi"; + reg = <0x18101000 0x100>; + interrupts = ; + clocks = <&clk_core CLK_SPI1>, <&cr_periph SYS_CLK_SPI1>; + clock-names = "sys", "spfi"; + dmas = <&mdc 1 0xffffffff 0>, <&mdc 2 0xffffffff 0>; + dma-names = "rx", "tx"; + img,supports-quad-mode; + spfi-max-frequency = <50000000>; + status = "disabled"; + + #address-cells = <1>; + #size-cells = <0>; + }; + + pwm: pwm@18101300 { + compatible = "img,pistachio-pwm"; + reg = <0x18101300 0x100>; + clocks = <&clk_periph PERIPH_CLK_PWM>, + <&cr_periph SYS_CLK_PWM>; + clock-names = "pwm", "sys"; + img,cr-periph = <&cr_periph>; + #pwm-cells = <2>; + status = "disabled"; + }; + + uart0: uart@18101400 { + compatible = "snps,dw-apb-uart"; + reg = <0x18101400 0x100>; + interrupts = ; + clocks = <&clk_core CLK_UART0>, <&cr_periph SYS_CLK_UART0>; + clock-names = "baudclk", "apb_pclk"; + assigned-clocks = <&clk_core CLK_UART0_INTERNAL_DIV>, + <&clk_core CLK_UART0_DIV>; + reg-shift = <2>; + reg-io-width = <4>; + pinctrl-0 = <&uart0_pins>, <&uart0_rts_cts_pins>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart1: uart@18101500 { + compatible = "snps,dw-apb-uart"; + reg = <0x18101500 0x100>; + interrupts = ; + clocks = <&clk_core CLK_UART1>, <&cr_periph SYS_CLK_UART1>; + clock-names = "baudclk", "apb_pclk"; + assigned-clocks = <&clk_core CLK_UART1_INTERNAL_DIV>, + <&clk_core CLK_UART1_DIV>; + assigned-clock-rates = <114278400>, <1843200>; + reg-shift = <2>; + reg-io-width = <4>; + pinctrl-0 = <&uart1_pins>; + pinctrl-names = "default"; + status = "disabled"; + }; + + adc: adc@18101600 { + compatible = "cosmic,10001-adc"; + reg = <0x18101600 0x24>; + adc-reserved-channels = <0x30>; + clocks = <&clk_core CLK_AUX_ADC>; + clock-names = "adc"; + assigned-clocks = <&clk_core CLK_AUX_ADC_INTERNAL_DIV>, + <&clk_core CLK_AUX_ADC_DIV>; + assigned-clock-rates = <100000000>, <1000000>; + status = "disabled"; + + #io-channel-cells = <1>; + }; + + pinctrl: pinctrl@18101c00 { + compatible = "img,pistachio-system-pinctrl"; + reg = <0x18101c00 0x400>; + + gpio0: gpio0 { + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 16>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio1 { + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 16 16>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio2 { + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 32 16>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio3 { + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 48 16>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio4: gpio4 { + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 64 16>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio5: gpio5 { + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 80 10>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + i2c0_pins: i2c0-pins { + pin_i2c0: i2c0 { + pins = "mfio28", "mfio29"; + function = "i2c0"; + drive-strength = <4>; + }; + }; + + i2c1_pins: i2c1-pins { + pin_i2c1: i2c1 { + pins = "mfio30", "mfio31"; + function = "i2c1"; + drive-strength = <4>; + }; + }; + + i2c2_pins: i2c2-pins { + pin_i2c2: i2c2 { + pins = "mfio32", "mfio33"; + function = "i2c2"; + drive-strength = <4>; + }; + }; + + i2c3_pins: i2c3-pins { + pin_i2c3: i2c3 { + pins = "mfio34", "mfio35"; + function = "i2c3"; + drive-strength = <4>; + }; + }; + + spim0_pins: spim0-pins { + pin_spim0: spim0 { + pins = "mfio9", "mfio10"; + function = "spim0"; + drive-strength = <4>; + }; + spim0_clk: spim0-clk { + pins = "mfio8"; + function = "spim0"; + drive-strength = <4>; + }; + }; + + spim0_cs0_alt_pin: spim0-cs0-alt-pin { + spim0-cs0 { + pins = "mfio2"; + drive-strength = <2>; + }; + }; + + spim0_cs1_pin: spim0-cs1-pin { + spim0-cs1 { + pins = "mfio1"; + drive-strength = <2>; + }; + }; + + spim0_cs2_pin: spim0-cs2-pin { + spim0-cs2 { + pins = "mfio55"; + drive-strength = <2>; + }; + }; + + spim0_cs2_alt_pin: spim0-cs2-alt-pin { + spim0-cs2 { + pins = "mfio28"; + drive-strength = <2>; + }; + }; + + spim0_cs3_pin: spim0-cs3-pin { + spim0-cs3 { + pins = "mfio56"; + drive-strength = <2>; + }; + }; + + spim0_cs3_alt_pin: spim0-cs3-alt-pin { + spim0-cs3 { + pins = "mfio29"; + drive-strength = <2>; + }; + }; + + spim0_cs4_pin: spim0-cs4-pin { + spim0-cs4 { + pins = "mfio57"; + drive-strength = <2>; + }; + }; + + spim0_cs4_alt_pin: spim0-cs4-alt-pin { + spim0-cs4 { + pins = "mfio30"; + drive-strength = <2>; + }; + }; + + spim1_pins: spim1-pins { + spim1 { + pins = "mfio3", "mfio4", "mfio5"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_quad_pins: spim1-quad-pins { + spim1-quad { + pins = "mfio6", "mfio7"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_cs0_pin: spim1-cs0-pins { + spim1-cs0 { + pins = "mfio0"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_cs1_pin: spim1-cs1-pin { + spim1-cs1 { + pins = "mfio1"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_cs1_alt_pin: spim1-cs1-alt-pin { + spim1-cs1 { + pins = "mfio58"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_cs2_pin: spim1-cs2-pin { + spim1-cs2 { + pins = "mfio2"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_cs2_alt0_pin: spim1-cs2-alt0-pin { + spim1-cs2 { + pins = "mfio31"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_cs2_alt1_pin: spim1-cs2-alt1-pin { + spim1-cs2 { + pins = "mfio55"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_cs3_pin: spim1-cs3-pin { + spim1-cs3 { + pins = "mfio56"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + spim1_cs4_pin: spim1-cs4-pin { + spim1-cs4 { + pins = "mfio57"; + function = "spim1"; + drive-strength = <2>; + }; + }; + + uart0_pins: uart0-pins { + uart0 { + pins = "mfio55", "mfio56"; + function = "uart0"; + drive-strength = <2>; + }; + }; + + uart0_rts_cts_pins: uart0-rts-cts-pins { + uart0-rts-cts { + pins = "mfio57", "mfio58"; + function = "uart0"; + drive-strength = <2>; + }; + }; + + uart1_pins: uart1-pins { + uart1 { + pins = "mfio59", "mfio60"; + function = "uart1"; + drive-strength = <2>; + }; + }; + + uart1_rts_cts_pins: uart1-rts-cts-pins { + uart1-rts-cts { + pins = "mfio1", "mfio2"; + function = "uart1"; + drive-strength = <2>; + }; + }; + + enet_pins: enet-pins { + pin_enet: enet { + pins = "mfio63", "mfio64", "mfio65", "mfio66", + "mfio67", "mfio68", "mfio69", "mfio70"; + function = "eth"; + slew-rate = <1>; + drive-strength = <4>; + }; + pin_enet_phy_clk: enet-phy-clk { + pins = "mfio71"; + function = "eth"; + slew-rate = <1>; + drive-strength = <8>; + }; + }; + + sdhost_pins: sdhost-pins { + pin_sdhost_clk: sdhost-clk { + pins = "mfio15"; + function = "sdhost"; + slew-rate = <1>; + drive-strength = <4>; + }; + pin_sdhost_cmd: sdhost-cmd { + pins = "mfio16"; + function = "sdhost"; + slew-rate = <1>; + drive-strength = <4>; + }; + pin_sdhost_data: sdhost-data { + pins = "mfio17", "mfio18", "mfio19", "mfio20", + "mfio21", "mfio22", "mfio23", "mfio24"; + function = "sdhost"; + slew-rate = <1>; + drive-strength = <4>; + }; + pin_sdhost_power_select: sdhost-power-select { + pins = "mfio25"; + function = "sdhost"; + slew-rate = <1>; + drive-strength = <2>; + }; + pin_sdhost_card_detect: sdhost-card-detect { + pins = "mfio26"; + function = "sdhost"; + drive-strength = <2>; + }; + pin_sdhost_write_protect: sdhost-write-protect { + pins = "mfio27"; + function = "sdhost"; + drive-strength = <2>; + }; + }; + + ir_pin: ir-pin { + ir-data { + pins = "mfio72"; + function = "ir"; + drive-strength = <2>; + }; + }; + + pwmpdm0_pin: pwmpdm0-pin { + pwmpdm0 { + pins = "mfio73"; + function = "pwmpdm"; + drive-strength = <2>; + }; + }; + + pwmpdm1_pin: pwmpdm1-pin { + pwmpdm1 { + pins = "mfio74"; + function = "pwmpdm"; + drive-strength = <2>; + }; + }; + + pwmpdm2_pin: pwmpdm2-pin { + pwmpdm2 { + pins = "mfio75"; + function = "pwmpdm"; + drive-strength = <2>; + }; + }; + + pwmpdm3_pin: pwmpdm3-pin { + pwmpdm3 { + pins = "mfio76"; + function = "pwmpdm"; + drive-strength = <2>; + }; + }; + + dac_clk_pin: dac-clk-pin { + pin_dac_clk: dac-clk { + pins = "mfio45"; + function = "i2s_dac_clk"; + drive-strength = <4>; + }; + }; + + i2s_mclk_pin: i2s-mclk-pin { + pin_i2s_mclk: i2s-mclk { + pins = "mfio36"; + function = "i2s_out"; + drive-strength = <4>; + }; + }; + + spdif_out_pin: spdif-out-pin { + spdif-out { + pins = "mfio61"; + function = "spdif_out"; + slew-rate = <1>; + drive-strength = <2>; + }; + }; + + spdif_in_pin: spdif-in-pin { + spdif-in { + pins = "mfio62"; + function = "spdif_in"; + drive-strength = <2>; + }; + }; + + i2s_out_pins: i2s-out-pins { + pins_i2s_out_clk: i2s-out-clk { + pins = "mfio37", "mfio38"; + function = "i2s_out"; + drive-strength = <4>; + }; + pins_i2s_out: i2s-out { + pins = "mfio39", "mfio40", + "mfio41", "mfio42", + "mfio43", "mfio44"; + function = "i2s_out"; + drive-strength = <2>; + }; + }; + + i2s_in_pins: i2s-in-pins { + i2s-in { + pins = "mfio47", "mfio48", "mfio49", + "mfio50", "mfio51", "mfio52", + "mfio53", "mfio54"; + function = "i2s_in"; + drive-strength = <2>; + }; + }; + }; + + timer: timer@18102000 { + compatible = "img,pistachio-gptimer"; + reg = <0x18102000 0x100>; + interrupts = ; + clocks = <&clk_periph PERIPH_CLK_COUNTER_FAST>, + <&cr_periph SYS_CLK_TIMER>; + clock-names = "fast", "sys"; + img,cr-periph = <&cr_periph>; + }; + + wdt: watchdog@18102100 { + compatible = "img,pdc-wdt"; + reg = <0x18102100 0x100>; + interrupts = ; + clocks = <&clk_periph PERIPH_CLK_WD>, <&cr_periph SYS_CLK_WD>; + clock-names = "wdt", "sys"; + assigned-clocks = <&clk_periph PERIPH_CLK_WD_PRE_DIV>, + <&clk_periph PERIPH_CLK_WD_DIV>; + assigned-clock-rates = <4000000>, <32768>; + }; + + ir: ir@18102200 { + compatible = "img,ir-rev1"; + reg = <0x18102200 0x100>; + interrupts = ; + clocks = <&clk_periph PERIPH_CLK_IR>, <&cr_periph SYS_CLK_IR>; + clock-names = "core", "sys"; + assigned-clocks = <&clk_periph PERIPH_CLK_IR_PRE_DIV>, + <&clk_periph PERIPH_CLK_IR_DIV>; + assigned-clock-rates = <4000000>, <32768>; + pinctrl-0 = <&ir_pin>; + pinctrl-names = "default"; + status = "disabled"; + }; + + usb: usb@18120000 { + compatible = "snps,dwc2"; + reg = <0x18120000 0x1c000>; + interrupts = ; + phys = <&usb_phy>; + phy-names = "usb2-phy"; + g-tx-fifo-size = <256 256 256 256>; + status = "disabled"; + }; + + enet: ethernet@18140000 { + compatible = "snps,dwmac"; + reg = <0x18140000 0x2000>; + interrupts = ; + interrupt-names = "macirq"; + clocks = <&clk_core CLK_ENET>, <&cr_periph SYS_CLK_ENET>; + clock-names = "stmmaceth", "pclk"; + assigned-clocks = <&clk_core CLK_ENET_MUX>, + <&clk_core CLK_ENET_DIV>; + assigned-clock-parents = <&clk_core CLK_SYS_INTERNAL_DIV>; + assigned-clock-rates = <0>, <50000000>; + pinctrl-0 = <&enet_pins>; + pinctrl-names = "default"; + phy-mode = "rmii"; + status = "disabled"; + }; + + sdhost: mmc@18142000 { + compatible = "img,pistachio-dw-mshc"; + reg = <0x18142000 0x400>; + interrupts = ; + clocks = <&clk_core CLK_SD_HOST>, <&cr_periph SYS_CLK_SD_HOST>; + clock-names = "ciu", "biu"; + pinctrl-0 = <&sdhost_pins>; + pinctrl-names = "default"; + fifo-depth = <0x20>; + num-slots = <1>; + clock-frequency = <50000000>; + bus-width = <8>; + cap-mmc-highspeed; + cap-sd-highspeed; + status = "disabled"; + }; + + sram: sram@1b000000 { + compatible = "mmio-sram"; + reg = <0x1b000000 0x10000>; + }; + + mdc: dma-controller@18143000 { + compatible = "img,pistachio-mdc-dma"; + reg = <0x18143000 0x1000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&cr_periph SYS_CLK_MDC>; + clock-names = "sys"; + + img,max-burst-multiplier = <16>; + img,cr-periph = <&cr_periph>; + + #dma-cells = <3>; + }; + + clk_core: clk@18144000 { + compatible = "img,pistachio-clk", "syscon"; + clocks = <&xtal>, <&cr_top EXT_CLK_AUDIO_IN>, + <&cr_top EXT_CLK_ENET_IN>; + clock-names = "xtal", "audio_refclk_ext_gate", + "ext_enet_in_gate"; + reg = <0x18144000 0x800>; + #clock-cells = <1>; + }; + + clk_periph: clk@18144800 { + compatible = "img,pistachio-clk-periph"; + reg = <0x18144800 0x1000>; + clocks = <&clk_core CLK_PERIPH_SYS>; + clock-names = "periph_sys_core"; + #clock-cells = <1>; + }; + + cr_periph: clk@18148000 { + compatible = "img,pistachio-cr-periph", "syscon", "simple-bus"; + reg = <0x18148000 0x1000>; + clocks = <&clk_periph PERIPH_CLK_SYS>; + clock-names = "sys"; + #clock-cells = <1>; + + pistachio_reset: reset-controller { + compatible = "img,pistachio-reset"; + #reset-cells = <1>; + }; + }; + + cr_top: clk@18149000 { + compatible = "img,pistachio-cr-top", "syscon"; + reg = <0x18149000 0x200>; + #clock-cells = <1>; + }; + + hash: hash@18149600 { + compatible = "img,hash-accelerator"; + reg = <0x18149600 0x100>, <0x18101100 0x4>; + interrupts = ; + dmas = <&mdc 8 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_HASH>, + <&clk_periph PERIPH_CLK_ROM>; + clock-names = "sys", "hash"; + }; + + gic: interrupt-controller@1bdc0000 { + compatible = "mti,gic"; + reg = <0x1bdc0000 0x20000>; + + interrupt-controller; + #interrupt-cells = <3>; + + timer { + compatible = "mti,gic-timer"; + interrupts = ; + clocks = <&clk_core CLK_MIPS>; + }; + }; + + usb_phy: usb-phy { + compatible = "img,pistachio-usb-phy"; + clocks = <&clk_core CLK_USB_PHY>; + clock-names = "usb_phy"; + assigned-clocks = <&clk_core CLK_USB_PHY_DIV>; + assigned-clock-rates = <50000000>; + img,refclk = <0x2>; + img,cr-top = <&cr_top>; + #phy-cells = <0>; + }; + + xtal: xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <52000000>; + clock-output-names = "xtal"; + }; +}; From daa10170da271ed82b34c39a5f10f993569eec79 Mon Sep 17 00:00:00 2001 From: Rahul Bedarkar Date: Fri, 14 Oct 2016 11:25:55 +0530 Subject: [PATCH 0131/1587] MIPS: DTS: img: add device tree for Marduk board Add support for Imagination Technologies' Marduk board which is based on Pistachio SoC. It is also known as Creator Ci40. Marduk is legacy name and will be there for decades. Documentation for this board can be found on https://docs.creatordev.io/ci40/ This patch adds initial support for board with following peripherals: * PWM based heartbeat LED * GPIO based buttons * SPI NOR flash on SPI1 * UART0 and UART1 * SD card * Ethernet * USB * PWM * ADC * I2C Signed-off-by: Rahul Bedarkar Acked-by: Rob Herring Acked-by: James Hartley Cc: Mark Rutland Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14394/ Signed-off-by: Ralf Baechle --- .../bindings/mips/img/pistachio-marduk.txt | 10 ++ MAINTAINERS | 6 + arch/mips/boot/dts/img/Makefile | 9 + arch/mips/boot/dts/img/pistachio_marduk.dts | 163 ++++++++++++++++++ 4 files changed, 188 insertions(+) create mode 100644 Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt create mode 100644 arch/mips/boot/dts/img/Makefile create mode 100644 arch/mips/boot/dts/img/pistachio_marduk.dts diff --git a/Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt b/Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt new file mode 100644 index 000000000000..2d5126d529a2 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt @@ -0,0 +1,10 @@ +Imagination Technologies' Pistachio SoC based Marduk Board +========================================================== + +Compatible string must be "img,pistachio-marduk", "img,pistachio" + +Hardware and other related documentation is available at +https://docs.creatordev.io/ci40/ + +It is also known as Creator Ci40. Marduk is legacy name and will +be there for decades. diff --git a/MAINTAINERS b/MAINTAINERS index eaa1586d137a..3d93f53383fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7692,6 +7692,12 @@ W: http://www.kernel.org/doc/man-pages L: linux-man@vger.kernel.org S: Maintained +MARDUK (CREATOR CI40) DEVICE TREE SUPPORT +M: Rahul Bedarkar +L: linux-mips@linux-mips.org +S: Maintained +F: arch/mips/boot/dts/img/pistachio_marduk.dts + MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER M: Andrew Lunn M: Vivien Didelot diff --git a/arch/mips/boot/dts/img/Makefile b/arch/mips/boot/dts/img/Makefile new file mode 100644 index 000000000000..69a65f0f82d2 --- /dev/null +++ b/arch/mips/boot/dts/img/Makefile @@ -0,0 +1,9 @@ +dtb-$(CONFIG_MACH_PISTACHIO) += pistachio_marduk.dtb + +obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y)) + +# Force kbuild to make empty built-in.o if necessary +obj- += dummy.o + +always := $(dtb-y) +clean-files := *.dtb *.dtb.S diff --git a/arch/mips/boot/dts/img/pistachio_marduk.dts b/arch/mips/boot/dts/img/pistachio_marduk.dts new file mode 100644 index 000000000000..cf9cebd52294 --- /dev/null +++ b/arch/mips/boot/dts/img/pistachio_marduk.dts @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2015, 2016 Imagination Technologies Ltd. + * + * 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. + * + * IMG Marduk board is also known as Creator Ci40. + */ + +/dts-v1/; + +#include "pistachio.dtsi" + +/ { + model = "IMG Marduk (Creator Ci40)"; + compatible = "img,pistachio-marduk", "img,pistachio"; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + ethernet0 = &enet; + spi0 = &spfi0; + spi1 = &spfi1; + }; + + chosen { + bootargs = "root=/dev/sda1 rootwait ro lpj=723968"; + stdout-path = "serial1:115200"; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + reg_1v8: fixed-regulator { + compatible = "regulator-fixed"; + regulator-name = "aux_adc_vref"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + internal_dac_supply: internal-dac-supply { + compatible = "regulator-fixed"; + regulator-name = "internal_dac_supply"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + leds { + compatible = "pwm-leds"; + heartbeat { + label = "marduk:red:heartbeat"; + pwms = <&pwm 3 300000>; + max-brightness = <255>; + linux,default-trigger = "heartbeat"; + }; + }; + + keys { + compatible = "gpio-keys"; + button@1 { + label = "Button 1"; + linux,code = <0x101>; /* BTN_1 */ + gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; + }; + button@2 { + label = "Button 2"; + linux,code = <0x102>; /* BTN_2 */ + gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&internal_dac { + VDD-supply = <&internal_dac_supply>; +}; + +&spfi1 { + status = "okay"; + + pinctrl-0 = <&spim1_pins>, <&spim1_quad_pins>, <&spim1_cs0_pin>, + <&spim1_cs1_pin>; + pinctrl-names = "default"; + cs-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio0 1 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "spansion,s25fl016k", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + }; +}; + +&uart0 { + status = "okay"; + assigned-clock-rates = <114278400>, <1843200>; +}; + +&uart1 { + status = "okay"; +}; + +&usb { + status = "okay"; +}; + +&enet { + status = "okay"; +}; + +&pin_enet { + drive-strength = <2>; +}; + +&pin_enet_phy_clk { + drive-strength = <2>; +}; + +&sdhost { + status = "okay"; + bus-width = <4>; + disable-wp; +}; + +&pin_sdhost_cmd { + drive-strength = <2>; +}; + +&pin_sdhost_data { + drive-strength = <2>; +}; + +&pwm { + status = "okay"; + + pinctrl-0 = <&pwmpdm0_pin>, <&pwmpdm1_pin>, <&pwmpdm2_pin>, + <&pwmpdm3_pin>; + pinctrl-names = "default"; +}; + +&adc { + status = "okay"; + vref-supply = <®_1v8>; + adc-reserved-channels = <0x10>; +}; + +&i2c2 { + status = "okay"; + clock-frequency = <400000>; + + tpm@20 { + compatible = "infineon,slb9645tt"; + reg = <0x20>; + }; + +}; + +&i2c3 { + status = "okay"; + clock-frequency = <400000>; +}; From e11124d8ffcdf893d64e0b29624fd88e0ae4ceac Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 17 Oct 2016 15:34:35 +0100 Subject: [PATCH 0132/1587] MIPS: Remove r2_emul_return from struct thread_info The r2_emul_return field in struct thread_info was used in order to take an alternate codepath when returning to userland, which (besides not implementing certain features) effectively used the eretnc instruction in place of eret. The difference is that eretnc doesn't clear LLBit, and therefore doesn't cause a linked load & store sequence to fail due to emulation like eret would. The reason eret would usually be used to clear LLBit is so that after context switching we ensure that a load performed by one task doesn't influence another task. However commit 7c151d3d5d7a ("MIPS: Make use of the ERETNC instruction on MIPS R6") which introduced the r2_emul_return field and conditional use of eretnc also for some reason began explicitly clearing LLBit during context switches - despite retaining the use of eret for everything but returns from the pre-r6 instruction emulation code. As LLBit is cleared upon context switches anyway, simplify this by using eretnc unconditionally for MIPSr6 kernels. This allows us to remove the 4 byte r2_emul_return boolean from struct thread_info, simplify the return to user code in entry.S and avoid the overhead of tracking & checking state which we don't need. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14408/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/stackframe.h | 4 ++++ arch/mips/include/asm/thread_info.h | 1 - arch/mips/kernel/asm-offsets.c | 1 - arch/mips/kernel/entry.S | 18 ------------------ arch/mips/kernel/traps.c | 2 -- 5 files changed, 4 insertions(+), 22 deletions(-) diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h index 2f182bdf024f..6c74a804fe98 100644 --- a/arch/mips/include/asm/stackframe.h +++ b/arch/mips/include/asm/stackframe.h @@ -364,9 +364,13 @@ .macro RESTORE_SP_AND_RET LONG_L sp, PT_R29(sp) +#ifdef CONFIG_CPU_MIPSR6 + eretnc +#else .set arch=r4000 eret .set mips0 +#endif .endm #endif diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index e309d8fcb516..b439e512792b 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -27,7 +27,6 @@ struct thread_info { unsigned long tp_value; /* thread pointer */ __u32 cpu; /* current CPU */ int preempt_count; /* 0 => preemptable, <0 => BUG */ - int r2_emul_return; /* 1 => Returning from R2 emulator */ mm_segment_t addr_limit; /* * thread address space limit: * 0x7fffffff for user-thead diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index a7277698d328..bb5c5d34ba81 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -97,7 +97,6 @@ void output_thread_info_defines(void) OFFSET(TI_TP_VALUE, thread_info, tp_value); OFFSET(TI_CPU, thread_info, cpu); OFFSET(TI_PRE_COUNT, thread_info, preempt_count); - OFFSET(TI_R2_EMUL_RET, thread_info, r2_emul_return); OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit); OFFSET(TI_REGS, thread_info, regs); DEFINE(_THREAD_SIZE, THREAD_SIZE); diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 7791840cf22c..8d83fc2a96b7 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -47,11 +47,6 @@ resume_userspace: local_irq_disable # make sure we dont miss an # interrupt setting need_resched # between sampling and return -#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR - lw k0, TI_R2_EMUL_RET($28) - bnez k0, restore_all_from_r2_emul -#endif - LONG_L a2, TI_FLAGS($28) # current->work andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) bnez t0, work_pending @@ -120,19 +115,6 @@ restore_partial: # restore partial frame RESTORE_SP_AND_RET .set at -#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR -restore_all_from_r2_emul: # restore full frame - .set noat - sw zero, TI_R2_EMUL_RET($28) # reset it - RESTORE_TEMP - RESTORE_AT - RESTORE_STATIC - RESTORE_SOME - LONG_L sp, PT_R29(sp) - eretnc - .set at -#endif - work_pending: andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS beqz t0, work_notifysig diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 9ea6959cd5bb..cb479be31a50 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1108,7 +1108,6 @@ asmlinkage void do_ri(struct pt_regs *regs) switch (status) { case 0: case SIGEMT: - task_thread_info(current)->r2_emul_return = 1; return; case SIGILL: goto no_r2_instr; @@ -1116,7 +1115,6 @@ asmlinkage void do_ri(struct pt_regs *regs) process_fpemu_return(status, ¤t->thread.cp0_baduaddr, fcr31); - task_thread_info(current)->r2_emul_return = 1; return; } } From 3b4b82399c4557666d348bed1aefc21c999e79a1 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 17 Oct 2016 15:34:36 +0100 Subject: [PATCH 0133/1587] MIPS: Cleanup LLBit handling in switch_to Commit 7c151d3d5d7a ("MIPS: Make use of the ERETNC instruction on MIPS R6") began clearing LLBit during context switches, but did so on all systems where it is writable for unclear reasons & did so from a macro with "software_ll_bit" in its name, which is intended to operate on the ll_bit variable used by ll/sc emulation for old CPUs. We do now need to clear LLBit on MIPSr6 systems where we'll use eretnc to return to userland, but we don't need to do so on MIPSr5 systems with a writable LLBit. Move the clear to its own appropriately named macro, do it only for MIPSr6 systems & comment about why. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14409/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/switch_to.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index c0ae27971e31..e610473d61b8 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -66,13 +66,18 @@ do { \ #define __mips_mt_fpaff_switch_to(prev) do { (void) (prev); } while (0) #endif -#define __clear_software_ll_bit() \ -do { if (cpu_has_rw_llb) { \ +/* + * Clear LLBit during context switches on MIPSr6 such that eretnc can be used + * unconditionally when returning to userland in entry.S. + */ +#define __clear_r6_hw_ll_bit() do { \ + if (cpu_has_mips_r6) \ write_c0_lladdr(0); \ - } else { \ - if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc)\ - ll_bit = 0; \ - } \ +} while (0) + +#define __clear_software_ll_bit() do { \ + if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc) \ + ll_bit = 0; \ } while (0) /* @@ -120,6 +125,7 @@ do { \ } \ clear_c0_status(ST0_CU2); \ } \ + __clear_r6_hw_ll_bit(); \ __clear_software_ll_bit(); \ if (cpu_has_userlocal) \ write_c0_userlocal(task_thread_info(next)->tp_value); \ From 9eaa9a82e5d6be2234482c3468ed56143c713729 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 17 Oct 2016 15:34:37 +0100 Subject: [PATCH 0134/1587] MIPS: Allow pre-r6 emulation on SMP MIPSr6 kernels There's no reason for the pre-r6 instruction emulation code to be limited to uniprocessor kernels. We already emulate atomic memory access instructions in a way that works for SMP systems, and nothing else should be affected. Remove the artificial limitation, allowing pre-r6 instruction emulation to be used with SMP kernels. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14410/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 40908304d1ef..9a7730219c93 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2288,7 +2288,7 @@ config MIPS_MT_FPAFF config MIPSR2_TO_R6_EMULATOR bool "MIPS R2-to-R6 emulator" - depends on CPU_MIPSR6 && !SMP + depends on CPU_MIPSR6 default y help Choose this option if you want to run non-R6 MIPS userland code. @@ -2296,8 +2296,6 @@ config MIPSR2_TO_R6_EMULATOR default. You can enable it using the 'mipsr2emu' kernel option. The only reason this is a build-time option is to save ~14K from the final kernel image. -comment "MIPS R2-to-R6 emulator is only available for UP kernels" - depends on SMP && CPU_MIPSR6 config MIPS_VPE_LOADER bool "VPE loader support." From 3ae34beb5ec9b04769708daf40cd5fff85cc537f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 17 Oct 2016 15:34:38 +0100 Subject: [PATCH 0135/1587] MIPS: Remove RESTORE_ALL_AND_RET The RESTORE_ALL_AND_RET macro is never used. Remove the dead code. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14411/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/stackframe.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h index 6c74a804fe98..eaa5a4d7d5e5 100644 --- a/arch/mips/include/asm/stackframe.h +++ b/arch/mips/include/asm/stackframe.h @@ -387,14 +387,6 @@ RESTORE_SP .endm - .macro RESTORE_ALL_AND_RET - RESTORE_TEMP - RESTORE_STATIC - RESTORE_AT - RESTORE_SOME - RESTORE_SP_AND_RET - .endm - /* * Move to kernel mode and disable interrupts. * Set cp0 enable bit as sign that we're running on the kernel stack From e31e4505b2c944c4e4c30e5ed983966537c4632f Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Sun, 4 Dec 2016 22:57:03 +0800 Subject: [PATCH 0136/1587] MIPS: Loongson1: Remove several redundant RTC-related macros Move the RTC-related macros to regs-rtc.h. Signed-off-by: Yang Ling Cc: keguang.zhang@gmail.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14642/ Signed-off-by: Ralf Baechle --- .../include/asm/mach-loongson32/loongson1.h | 7 ++--- .../include/asm/mach-loongson32/regs-rtc.h | 23 ++++++++++++++++ arch/mips/loongson32/common/platform.c | 27 ++++++++----------- 3 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 arch/mips/include/asm/mach-loongson32/regs-rtc.h diff --git a/arch/mips/include/asm/mach-loongson32/loongson1.h b/arch/mips/include/asm/mach-loongson32/loongson1.h index ec7efd0de744..84c28a8995ae 100644 --- a/arch/mips/include/asm/mach-loongson32/loongson1.h +++ b/arch/mips/include/asm/mach-loongson32/loongson1.h @@ -3,9 +3,9 @@ * * Register mappings for Loongson 1 * - * 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 + * 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. */ @@ -52,6 +52,7 @@ #include #include #include +#include #include #endif /* __ASM_MACH_LOONGSON32_LOONGSON1_H */ diff --git a/arch/mips/include/asm/mach-loongson32/regs-rtc.h b/arch/mips/include/asm/mach-loongson32/regs-rtc.h new file mode 100644 index 000000000000..e67fda24cf6f --- /dev/null +++ b/arch/mips/include/asm/mach-loongson32/regs-rtc.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016 Yang Ling + * + * Loongson 1 RTC timer Register Definitions. + * + * 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. + */ + +#ifndef __ASM_MACH_LOONGSON32_REGS_RTC_H +#define __ASM_MACH_LOONGSON32_REGS_RTC_H + +#define LS1X_RTC_REG(x) \ + ((void __iomem *)KSEG1ADDR(LS1X_RTC_BASE + (x))) + +#define LS1X_RTC_CTRL LS1X_RTC_REG(0x40) + +#define RTC_EXTCLK_OK (BIT(5) | BIT(8)) +#define RTC_EXTCLK_EN BIT(8) + +#endif /* __ASM_MACH_LOONGSON32_REGS_RTC_H */ diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index beff0852c6a4..18c2959afe07 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -1,9 +1,9 @@ /* * Copyright (c) 2011-2016 Zhang, Keguang * - * 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 + * 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. */ @@ -23,10 +23,6 @@ #include #include -#define LS1X_RTC_CTRL ((void __iomem *)KSEG1ADDR(LS1X_RTC_BASE + 0x40)) -#define RTC_EXTCLK_OK (BIT(5) | BIT(8)) -#define RTC_EXTCLK_EN BIT(8) - /* 8250/16550 compatible UART */ #define LS1X_UART(_id) \ { \ @@ -70,15 +66,6 @@ void __init ls1x_serial_set_uartclk(struct platform_device *pdev) p->uartclk = clk_get_rate(clk); } -void __init ls1x_rtc_set_extclk(struct platform_device *pdev) -{ - u32 val; - - val = __raw_readl(LS1X_RTC_CTRL); - if (!(val & RTC_EXTCLK_OK)) - __raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL); -} - /* CPUFreq */ static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = { .clk_name = "cpu_clk", @@ -357,6 +344,14 @@ struct platform_device ls1x_ehci_pdev = { }; /* Real Time Clock */ +void __init ls1x_rtc_set_extclk(struct platform_device *pdev) +{ + u32 val = __raw_readl(LS1X_RTC_CTRL); + + if (!(val & RTC_EXTCLK_OK)) + __raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL); +} + struct platform_device ls1x_rtc_pdev = { .name = "ls1x-rtc", .id = -1, From 5e73ad3ffcebc72bce9a662d3e59f0cc9fb3f4ef Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Sun, 4 Dec 2016 23:05:40 +0800 Subject: [PATCH 0137/1587] MIPS: Loongson1: Add watchdog support for Loongson1 board The patch adds watchdog support for Loongson1 board. Signed-off-by: Yang Ling Cc: keguang.zhang@gmail.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14644/ Signed-off-by: Ralf Baechle --- arch/mips/configs/loongson1b_defconfig | 4 ++++ arch/mips/configs/loongson1c_defconfig | 4 ++++ arch/mips/include/asm/mach-loongson32/platform.h | 9 +++++---- arch/mips/loongson32/common/platform.c | 16 ++++++++++++++++ arch/mips/loongson32/ls1b/board.c | 7 ++++--- arch/mips/loongson32/ls1c/board.c | 7 ++++--- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/arch/mips/configs/loongson1b_defconfig b/arch/mips/configs/loongson1b_defconfig index c442f27685f4..914c867887bd 100644 --- a/arch/mips/configs/loongson1b_defconfig +++ b/arch/mips/configs/loongson1b_defconfig @@ -74,6 +74,10 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_GPIOLIB=y CONFIG_GPIO_LOONGSON1=y # CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_LOONGSON1_WDT=y # CONFIG_VGA_CONSOLE is not set CONFIG_HID_GENERIC=m CONFIG_USB_HID=m diff --git a/arch/mips/configs/loongson1c_defconfig b/arch/mips/configs/loongson1c_defconfig index 2304d4165773..68e42eff908e 100644 --- a/arch/mips/configs/loongson1c_defconfig +++ b/arch/mips/configs/loongson1c_defconfig @@ -75,6 +75,10 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_GPIOLIB=y CONFIG_GPIO_LOONGSON1=y # CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_LOONGSON1_WDT=y # CONFIG_VGA_CONSOLE is not set CONFIG_HID_GENERIC=m CONFIG_USB_HID=m diff --git a/arch/mips/include/asm/mach-loongson32/platform.h b/arch/mips/include/asm/mach-loongson32/platform.h index 7adc31364939..8f8fa43ba095 100644 --- a/arch/mips/include/asm/mach-loongson32/platform.h +++ b/arch/mips/include/asm/mach-loongson32/platform.h @@ -1,9 +1,9 @@ /* * Copyright (c) 2011 Zhang, Keguang * - * 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 + * 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. */ @@ -25,11 +25,12 @@ extern struct platform_device ls1x_gpio0_pdev; extern struct platform_device ls1x_gpio1_pdev; extern struct platform_device ls1x_nand_pdev; extern struct platform_device ls1x_rtc_pdev; +extern struct platform_device ls1x_wdt_pdev; void __init ls1x_clk_init(void); void __init ls1x_dma_set_platdata(struct plat_ls1x_dma *pdata); void __init ls1x_nand_set_platdata(struct plat_ls1x_nand *pdata); -void __init ls1x_serial_set_uartclk(struct platform_device *pdev); void __init ls1x_rtc_set_extclk(struct platform_device *pdev); +void __init ls1x_serial_set_uartclk(struct platform_device *pdev); #endif /* __ASM_MACH_LOONGSON32_PLATFORM_H */ diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index 18c2959afe07..a3dabe940b03 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -356,3 +356,19 @@ struct platform_device ls1x_rtc_pdev = { .name = "ls1x-rtc", .id = -1, }; + +/* Watchdog */ +static struct resource ls1x_wdt_resources[] = { + { + .start = LS1X_WDT_BASE, + .end = LS1X_WDT_BASE + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device ls1x_wdt_pdev = { + .name = "ls1x-wdt", + .id = -1, + .num_resources = ARRAY_SIZE(ls1x_wdt_resources), + .resource = ls1x_wdt_resources, +}; diff --git a/arch/mips/loongson32/ls1b/board.c b/arch/mips/loongson32/ls1b/board.c index 38a1d404be1b..01aceaace314 100644 --- a/arch/mips/loongson32/ls1b/board.c +++ b/arch/mips/loongson32/ls1b/board.c @@ -1,9 +1,9 @@ /* * Copyright (c) 2011-2016 Zhang, Keguang * - * 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 + * 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. */ @@ -72,6 +72,7 @@ static struct platform_device *ls1b_platform_devices[] __initdata = { &ls1x_gpio1_pdev, &ls1x_nand_pdev, &ls1x_rtc_pdev, + &ls1x_wdt_pdev, }; static int __init ls1b_platform_init(void) diff --git a/arch/mips/loongson32/ls1c/board.c b/arch/mips/loongson32/ls1c/board.c index a96bed5e3ea6..eb2d913c694f 100644 --- a/arch/mips/loongson32/ls1c/board.c +++ b/arch/mips/loongson32/ls1c/board.c @@ -1,9 +1,9 @@ /* * Copyright (c) 2016 Yang Ling * - * 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 + * 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. */ @@ -13,6 +13,7 @@ static struct platform_device *ls1c_platform_devices[] __initdata = { &ls1x_uart_pdev, &ls1x_eth0_pdev, &ls1x_rtc_pdev, + &ls1x_wdt_pdev, }; static int __init ls1c_platform_init(void) From 02564fc89d3d92a8d4fa6e11c348000b70e9568d Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Tue, 13 Dec 2016 11:46:41 +0100 Subject: [PATCH 0138/1587] ralink: Introduce fw_passed_dtb to arch/mips/ralink This patch adds fw_passed_dtb to arch/mips/ralink to support CONFIG_MIPS_RAW_APPENDED_DTB. Furthermore it adds a check that __dtb_start is not the same address as __dtb_end. Signed-off-by: Tobias Wolf Acked-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14662/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/of.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c index 0aa67a2d0ae6..4c843e039b96 100644 --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c @@ -66,13 +66,21 @@ static int __init early_init_dt_find_memory(unsigned long node, void __init plat_mem_setup(void) { + void *dtb = NULL; + set_io_port_base(KSEG1); /* * Load the builtin devicetree. This causes the chosen node to be - * parsed resulting in our memory appearing + * parsed resulting in our memory appearing. fw_passed_dtb is used + * by CONFIG_MIPS_APPENDED_RAW_DTB as well. */ - __dt_setup_arch(__dtb_start); + if (fw_passed_dtb) + dtb = (void *)fw_passed_dtb; + else if (__dtb_start != __dtb_end) + dtb = (void *)__dtb_start; + + __dt_setup_arch(dtb); of_scan_flat_dt(early_init_dt_find_memory, NULL); if (memory_dtb) From 3ec754410cb3e931a6c4920b1a150f21a94a2bf4 Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Wed, 23 Nov 2016 10:40:07 +0100 Subject: [PATCH 0139/1587] of: Add check to of_scan_flat_dt() before accessing initial_boot_params An empty __dtb_start to __dtb_end section might result in initial_boot_params being null for arch/mips/ralink. This showed that the boot process hangs indefinitely in of_scan_flat_dt(). Signed-off-by: Tobias Wolf Cc: Sergei Shtylyov Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14605/ Signed-off-by: Ralf Baechle --- drivers/of/fdt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index c9b5cac03b36..82967b07f7be 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -738,9 +738,12 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, const char *pathp; int offset, rc = 0, depth = -1; - for (offset = fdt_next_node(blob, -1, &depth); - offset >= 0 && depth >= 0 && !rc; - offset = fdt_next_node(blob, offset, &depth)) { + if (!blob) + return 0; + + for (offset = fdt_next_node(blob, -1, &depth); + offset >= 0 && depth >= 0 && !rc; + offset = fdt_next_node(blob, offset, &depth)) { pathp = fdt_get_name(blob, offset, NULL); if (*pathp == '/') From 16190b3639375baa887cfb2c35d3f4edb17902bc Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 30 Nov 2016 23:58:07 +0100 Subject: [PATCH 0140/1587] MIPS: lantiq: Refresh default configuration Just generate a configuration based on this default configuration and store it again. This removed some old configuration options. Signed-off-by: Hauke Mehrtens Acked-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14629/ Signed-off-by: Ralf Baechle --- arch/mips/configs/xway_defconfig | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/mips/configs/xway_defconfig b/arch/mips/configs/xway_defconfig index 8987846240f7..0ccb6420864e 100644 --- a/arch/mips/configs/xway_defconfig +++ b/arch/mips/configs/xway_defconfig @@ -2,11 +2,11 @@ CONFIG_LANTIQ=y CONFIG_XRX200_PHY_FW=y CONFIG_CPU_MIPS32_R2=y # CONFIG_COMPACTION is not set -# CONFIG_CROSS_MEMORY_ATTACH is not set CONFIG_HZ_100=y # CONFIG_SECCOMP is not set # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y +# CONFIG_CROSS_MEMORY_ATTACH is not set CONFIG_HIGH_RES_TIMERS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set @@ -35,12 +35,10 @@ CONFIG_IP_ROUTE_MULTIPATH=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_MROUTE=y CONFIG_IP_MROUTE_MULTIPLE_TABLES=y -CONFIG_ARPD=y CONFIG_SYN_COOKIES=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set # CONFIG_INET_DIAG is not set CONFIG_TCP_CONG_ADVANCED=y # CONFIG_TCP_CONG_BIC is not set @@ -62,7 +60,6 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m CONFIG_NETFILTER_XT_MATCH_STATE=m CONFIG_NF_CONNTRACK_IPV4=m -# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m @@ -151,9 +148,6 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_SCHED_DEBUG is not set # CONFIG_FTRACE is not set CONFIG_CMDLINE_BOOL=y -CONFIG_CRYPTO_MANAGER=m CONFIG_CRYPTO_ARC4=m -# CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRC_ITU_T=m CONFIG_CRC32_SARWATE=y -CONFIG_AVERAGE=y From d9ae4f18c0d2a4781c1338e6ca0f21a1e96cdb03 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 30 Nov 2016 23:58:08 +0100 Subject: [PATCH 0141/1587] MIPS: Lantiq: Activate more drivers in default configuration This activates the following functionalities: * SMP support (used on xRX200) * PCI support * NAND driver * PHY driver * UART * Watchdog * USB 2.0 controller These driver are driving different IP cores found on the supported SoCs. Signed-off-by: Hauke Mehrtens Acked-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14628/ Signed-off-by: Ralf Baechle --- arch/mips/configs/xway_defconfig | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/mips/configs/xway_defconfig b/arch/mips/configs/xway_defconfig index 0ccb6420864e..4365108bef77 100644 --- a/arch/mips/configs/xway_defconfig +++ b/arch/mips/configs/xway_defconfig @@ -1,7 +1,11 @@ CONFIG_LANTIQ=y +CONFIG_PCI_LANTIQ=y CONFIG_XRX200_PHY_FW=y CONFIG_CPU_MIPS32_R2=y +CONFIG_MIPS_MT_SMP=y +CONFIG_MIPS_VPE_LOADER=y # CONFIG_COMPACTION is not set +CONFIG_NR_CPUS=2 CONFIG_HZ_100=y # CONFIG_SECCOMP is not set # CONFIG_LOCALVERSION_AUTO is not set @@ -22,8 +26,8 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_CFQ is not set +CONFIG_PCI=y # CONFIG_COREDUMP is not set -# CONFIG_SUSPEND is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -81,6 +85,8 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_LANTIQ=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_XWAY=y CONFIG_EEPROM_93CX6=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y @@ -88,6 +94,7 @@ CONFIG_NETDEVICES=y CONFIG_LANTIQ_ETOP=y # CONFIG_NET_VENDOR_WIZNET is not set CONFIG_PHYLIB=y +CONFIG_INTEL_XWAY_PHY=y CONFIG_PPP=m CONFIG_PPP_FILTER=y CONFIG_PPP_MULTILINK=y @@ -108,17 +115,21 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_RUNTIME_UARTS=2 CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_LANTIQ=y CONFIG_SPI=y CONFIG_GPIO_MM_LANTIQ=y CONFIG_GPIO_STP_XWAY=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y +CONFIG_LANTIQ_WDT=y # CONFIG_HID is not set # CONFIG_USB_HID is not set CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_DEBUG=y +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_PCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_TRIGGERS=y From 109c32ffd89d64dd99a775f2f50443bee38b63e9 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 24 Nov 2016 17:32:45 +0000 Subject: [PATCH 0142/1587] MIPS: Add support for ARCH_MMAP_RND_{COMPAT_}BITS arch_mmap_rnd() uses hard-coded limits of 16MB for the randomisation of mmap within 32bit processes and 256MB in 64bit processes. Since v4.4 other arches support tuning this value in /proc/sys/vm/mmap_rnd_bits. Add support for this to MIPS. Set the minimum(default) number of bits randomisation for 32bit to 8 - which with 4k pagesize is unchanged from the current 16MB total randomness. The minimum(default) for 64bit is 12bits, again with 4k pagesize this is the same as the current 256MB. This patch is necessary for MIPS32 to pass the Android CTS tests, with the number of random bits set to 15. Signed-off-by: Matt Redfearn Reviewed-by: Kees Cook Cc: Paul Gortmaker Cc: Daniel Cashman Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: kernel-hardening@lists.openwall.com Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14617/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 16 ++++++++++++++++ arch/mips/mm/mmap.c | 10 +++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 9a7730219c93..6ed1a0af33e9 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -14,6 +14,8 @@ config MIPS select HAVE_PERF_EVENTS select PERF_USE_VMALLOC select HAVE_ARCH_KGDB + select HAVE_ARCH_MMAP_RND_BITS if MMU + select HAVE_ARCH_MMAP_RND_COMPAT_BITS if MMU && COMPAT select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_CBPF_JIT if !CPU_MICROMIPS @@ -3073,6 +3075,20 @@ config MMU bool default y +config ARCH_MMAP_RND_BITS_MIN + default 12 if 64BIT + default 8 + +config ARCH_MMAP_RND_BITS_MAX + default 18 if 64BIT + default 15 + +config ARCH_MMAP_RND_COMPAT_BITS_MIN + default 8 + +config ARCH_MMAP_RND_COMPAT_BITS_MAX + default 15 + config I8253 bool select CLKSRC_I8253 diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index d08ea3ff0f53..d6d92c02308d 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c @@ -146,14 +146,14 @@ unsigned long arch_mmap_rnd(void) { unsigned long rnd; - rnd = get_random_long(); - rnd <<= PAGE_SHIFT; +#ifdef CONFIG_COMPAT if (TASK_IS_32BIT_ADDR) - rnd &= 0xfffffful; + rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1); else - rnd &= 0xffffffful; +#endif /* CONFIG_COMPAT */ + rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1); - return rnd; + return rnd << PAGE_SHIFT; } void arch_pick_mmap_layout(struct mm_struct *mm) From c83c2eed67e578576acf08611bfb630bd199714b Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Fri, 2 Dec 2016 09:58:28 +0100 Subject: [PATCH 0143/1587] MIPS: kexec: remove SMP_DUMP SMP_DUMP has been added as a new IPI signal when kexec support was added for Cavium Octeon CPUs ('commit 7aa1c8f47e7e ("MIPS: kdump: Add support")'. However, the new signal doesn't appear to ever have a proper handler added (octeon_message_functions[] array has an empty handler for it), and generic IPI handlers now trigger a BUG() on unhandled signal. As the method is unused remove it completely and replace its only invocation with a smp_call_function(). [ralf@linux-mips.org: Renumber SMP_ASK_C0COUNT to avoid numbering gaps.] Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14630/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/smp.h | 8 +------- arch/mips/kernel/crash.c | 2 +- arch/mips/kernel/smp.c | 17 ----------------- 3 files changed, 2 insertions(+), 25 deletions(-) diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index f8c5faa93584..98a117a05fbc 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -42,9 +42,7 @@ extern int __cpu_logical_map[NR_CPUS]; #define SMP_CALL_FUNCTION 0x2 /* Octeon - Tell another core to flush its icache */ #define SMP_ICACHE_FLUSH 0x4 -/* Used by kexec crashdump to save all cpu's state */ -#define SMP_DUMP 0x8 -#define SMP_ASK_C0COUNT 0x10 +#define SMP_ASK_C0COUNT 0x8 /* Mask of CPUs which are currently definitely operating coherently */ extern cpumask_t cpu_coherent_mask; @@ -111,8 +109,4 @@ static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask) mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION); } -#if defined(CONFIG_KEXEC) -extern void (*dump_ipi_function_ptr)(void *); -void dump_send_ipi(void (*dump_ipi_callback)(void *)); -#endif #endif /* __ASM_SMP_H */ diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index 1723b1762297..5a71518be0f1 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -56,7 +56,7 @@ static void crash_kexec_prepare_cpus(void) ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ - dump_send_ipi(crash_shutdown_secondary); + smp_call_function(crash_shutdown_secondary, NULL, 0); smp_wmb(); /* diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 0a831f63b0ec..8c60a296294c 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -638,23 +638,6 @@ void flush_tlb_one(unsigned long vaddr) EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(flush_tlb_one); -#if defined(CONFIG_KEXEC) -void (*dump_ipi_function_ptr)(void *) = NULL; -void dump_send_ipi(void (*dump_ipi_callback)(void *)) -{ - int i; - int cpu = smp_processor_id(); - - dump_ipi_function_ptr = dump_ipi_callback; - smp_mb(); - for_each_online_cpu(i) - if (i != cpu) - mp_ops->send_ipi_single(i, SMP_DUMP); - -} -EXPORT_SYMBOL(dump_send_ipi); -#endif - #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST static DEFINE_PER_CPU(atomic_t, tick_broadcast_count); From bff323d5653cf0ad83391b5a5f4ec7cc32acad1a Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Fri, 2 Dec 2016 09:58:29 +0100 Subject: [PATCH 0144/1587] MIPS: Kconfig: Fix indentation for kexec-related entries Kconfig entries are not aligned properly, so remove incorrect whitespace. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14631/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 6ed1a0af33e9..ffd2f67b1aa2 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2828,8 +2828,8 @@ config KEXEC made. config CRASH_DUMP - bool "Kernel crash dumps" - help + bool "Kernel crash dumps" + help Generate crash dump after being started by kexec. This should be normally only set in special crash dump kernels which are loaded in the main kernel with kexec-tools into @@ -2839,11 +2839,11 @@ config CRASH_DUMP PHYSICAL_START. config PHYSICAL_START - hex "Physical address where the kernel is loaded" - default "0xffffffff84000000" if 64BIT - default "0x84000000" if 32BIT - depends on CRASH_DUMP - help + hex "Physical address where the kernel is loaded" + default "0xffffffff84000000" if 64BIT + default "0x84000000" if 32BIT + depends on CRASH_DUMP + help This gives the CKSEG0 or KSEG0 address where the kernel is loaded. If you plan to use kernel for capturing the crash dump change this value to start of the reserved region (the "X" value as From 08c941bf6ec523d666a78f86e3d696ed45dfb6e5 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Mon, 21 Nov 2016 11:23:38 +0100 Subject: [PATCH 0145/1587] MIPS: Move register dump routines out of ptrace code Current register dump methods for MIPS are implemented inside ptrace methods, but there will be other uses in the kernel for them, so keep them separately in process.c and use those definitions for ptrace instead. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14587/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/elf.h | 3 +++ arch/mips/kernel/process.c | 44 +++++++++++++++++++++++++++++++++++++ arch/mips/kernel/ptrace.c | 34 ++-------------------------- 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 2b3dc2973670..f61a4a14bb56 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -210,6 +210,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; +void mips_dump_regs32(u32 *uregs, const struct pt_regs *regs); +void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs); + #ifdef CONFIG_32BIT /* * This is used to ensure we don't load something for the wrong architecture. diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 3da0161bdf84..803e255b6fc3 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -729,3 +729,47 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) return 0; } + +#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) +void mips_dump_regs32(u32 *uregs, const struct pt_regs *regs) +{ + unsigned int i; + + for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) { + /* k0/k1 are copied as zero. */ + if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27) + uregs[i] = 0; + else + uregs[i] = regs->regs[i - MIPS32_EF_R0]; + } + + uregs[MIPS32_EF_LO] = regs->lo; + uregs[MIPS32_EF_HI] = regs->hi; + uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc; + uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr; + uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status; + uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause; +} +#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */ + +#ifdef CONFIG_64BIT +void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs) +{ + unsigned int i; + + for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) { + /* k0/k1 are copied as zero. */ + if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27) + uregs[i] = 0; + else + uregs[i] = regs->regs[i - MIPS64_EF_R0]; + } + + uregs[MIPS64_EF_LO] = regs->lo; + uregs[MIPS64_EF_HI] = regs->hi; + uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc; + uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr; + uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status; + uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause; +} +#endif /* CONFIG_64BIT */ diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index c8ba26072132..fdef26382c37 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -294,23 +294,8 @@ static int gpr32_get(struct task_struct *target, { struct pt_regs *regs = task_pt_regs(target); u32 uregs[ELF_NGREG] = {}; - unsigned i; - - for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) { - /* k0/k1 are copied as zero. */ - if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27) - continue; - - uregs[i] = regs->regs[i - MIPS32_EF_R0]; - } - - uregs[MIPS32_EF_LO] = regs->lo; - uregs[MIPS32_EF_HI] = regs->hi; - uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc; - uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr; - uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status; - uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause; + mips_dump_regs32(uregs, regs); return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, sizeof(uregs)); } @@ -373,23 +358,8 @@ static int gpr64_get(struct task_struct *target, { struct pt_regs *regs = task_pt_regs(target); u64 uregs[ELF_NGREG] = {}; - unsigned i; - - for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) { - /* k0/k1 are copied as zero. */ - if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27) - continue; - - uregs[i] = regs->regs[i - MIPS64_EF_R0]; - } - - uregs[MIPS64_EF_LO] = regs->lo; - uregs[MIPS64_EF_HI] = regs->hi; - uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc; - uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr; - uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status; - uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause; + mips_dump_regs64(uregs, regs); return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, sizeof(uregs)); } From 39a3cb27c123df8e8461291cc9e86f1ac3f0ea06 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Mon, 21 Nov 2016 11:23:39 +0100 Subject: [PATCH 0146/1587] MIPS: elfcore: add correct copy_regs implementations MIPS does not currently define ELF_CORE_COPY_REGS macros and as a result the generic implementation is used. The generic version attempts to do directly map (struct pt_regs) into (elf_gregset_t), which isn't correct for MIPS platforms and also triggers a BUG() at runtime in include/linux/elfcore.h:16 (BUG_ON(sizeof(*elfregs) != sizeof(*regs))) [ralf@linux-mips.org: Add semicolons to the macro definitions as I do not apply https://patchwork.linux-mips.org/patch/14588/ for now.] Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14586/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/elf.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index f61a4a14bb56..7a6c466e5f2a 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -224,6 +224,9 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs); */ #define ELF_CLASS ELFCLASS32 +#define ELF_CORE_COPY_REGS(dest, regs) \ + mips_dump_regs32((u32 *)&(dest), (regs)); + #endif /* CONFIG_32BIT */ #ifdef CONFIG_64BIT @@ -237,6 +240,9 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs); */ #define ELF_CLASS ELFCLASS64 +#define ELF_CORE_COPY_REGS(dest, regs) \ + mips_dump_regs64((u64 *)&(dest), (regs)); + #endif /* CONFIG_64BIT */ /* From 269aa43aad0f96673478fe2446abe54d7ad42e8f Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:43 +0100 Subject: [PATCH 0147/1587] MIPS: Do not request resources for crashkernel if one isn't defined When KEXEC is enabled but crashkernel details are not passed through the kernel commandline unnecessary resources are requested (start==end==0) Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14607/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f66e5ce505b2..0058feaa65e5 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -672,6 +672,9 @@ static void __init request_crashkernel(struct resource *res) { int ret; + if (crashk_res.start == crashk_res.end) + return; + ret = request_resource(res, &crashk_res); if (!ret) pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n", From e89ef66d7682f031f026eee6bba03c8c2248d2a9 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:44 +0100 Subject: [PATCH 0148/1587] MIPS: init: Ensure reserved memory regions are not added to bootmem Memories managed through boot_mem_map are generally expected to define non-crossing areas. However, if part of a larger memory block is marked as reserved, it would still be added to bootmem allocator as an available block and could end up being overwritten by the allocator. Prevent this by explicitly marking the memory as reserved it if exists in the range used by bootmem allocator. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14608/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 0058feaa65e5..8ebad247ce82 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -483,6 +483,10 @@ static void __init bootmem_init(void) continue; default: /* Not usable memory */ + if (start > min_low_pfn && end < max_low_pfn) + reserve_bootmem(boot_mem_map.map[i].addr, + boot_mem_map.map[i].size, + BOOTMEM_DEFAULT); continue; } From d9b5b658210f28ed9f70c757d553e679d76e2986 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:45 +0100 Subject: [PATCH 0149/1587] MIPS: init: Ensure bootmem does not corrupt reserved memory Current init code initialises bootmem allocator with all of the low memory that it assumes is available, but does not check for reserved memory block, which can lead to corruption of data that may be stored there. Move bootmem's allocation map to a location that does not cross any reserved regions Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14609/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 74 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 8ebad247ce82..64b38d400987 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -153,6 +153,35 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add add_memory_region(start, size, BOOT_MEM_RAM); } +bool __init memory_region_available(phys_addr_t start, phys_addr_t size) +{ + int i; + bool in_ram = false, free = true; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + phys_addr_t start_, end_; + + start_ = boot_mem_map.map[i].addr; + end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size; + + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + if (start >= start_ && start + size <= end_) + in_ram = true; + break; + case BOOT_MEM_RESERVED: + if ((start >= start_ && start < end_) || + (start < start_ && start + size >= start_)) + free = false; + break; + default: + continue; + } + } + + return in_ram && free; +} + static void __init print_memory_map(void) { int i; @@ -332,11 +361,19 @@ static void __init bootmem_init(void) #else /* !CONFIG_SGI_IP27 */ +static unsigned long __init bootmap_bytes(unsigned long pages) +{ + unsigned long bytes = DIV_ROUND_UP(pages, 8); + + return ALIGN(bytes, sizeof(long)); +} + static void __init bootmem_init(void) { unsigned long reserved_end; unsigned long mapstart = ~0UL; unsigned long bootmap_size; + bool bootmap_valid = false; int i; /* @@ -429,12 +466,43 @@ static void __init bootmem_init(void) mapstart = max(mapstart, (unsigned long)PFN_UP(__pa(initrd_end))); #endif + /* + * check that mapstart doesn't overlap with any of + * memory regions that have been reserved through eg. DTB + */ + bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn); + + bootmap_valid = memory_region_available(PFN_PHYS(mapstart), + bootmap_size); + for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) { + unsigned long mapstart_addr; + + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RESERVED: + mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + if (PHYS_PFN(mapstart_addr) < mapstart) + break; + + bootmap_valid = memory_region_available(mapstart_addr, + bootmap_size); + if (bootmap_valid) + mapstart = PHYS_PFN(mapstart_addr); + break; + default: + break; + } + } + + if (!bootmap_valid) + panic("No memory area to place a bootmap bitmap"); + /* * Initialize the boot-time allocator with low memory only. */ - bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart, - min_low_pfn, max_low_pfn); - + if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart, + min_low_pfn, max_low_pfn)) + panic("Unexpected memory size required for bootmap"); for (i = 0; i < boot_mem_map.nr_map; i++) { unsigned long start, end; From 73346081cac18732a959be580a90abc707dea52a Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:46 +0100 Subject: [PATCH 0150/1587] MIPS: Use early_init_fdt_reserve_self to protect DTB location early_init_fdt_reserve_self is used to tell the boot memory allocator that a memory is occupied by the DTB, so add it in the MIPS init code to ensure information about the DTB is added to the boot memory array. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14610/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/prom.c | 7 +++++++ arch/mips/kernel/setup.c | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 5fcec3032f38..0dbcd152a1a9 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -49,6 +49,13 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)); } +int __init early_init_dt_reserve_memory_arch(phys_addr_t base, + phys_addr_t size, bool nomap) +{ + add_memory_region(base, size, BOOT_MEM_RESERVED); + return 0; +} + void __init __dt_setup_arch(void *bph) { if (!early_init_dt_scan(bph)) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 64b38d400987..c22f0fdd4cfb 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -832,6 +833,9 @@ static void __init arch_mem_init(char **cmdline_p) print_memory_map(); } + early_init_fdt_reserve_self(); + early_init_fdt_scan_reserved_mem(); + bootmem_init(); #ifdef CONFIG_PROC_VMCORE if (setup_elfcorehdr && setup_elfcorehdr_size) { From 0063fdede69b2cc6f861aab0641f7e25f451def9 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:47 +0100 Subject: [PATCH 0151/1587] MIPS: platform: Allow for DTB to be moved during kernel relocation Add plat_fdt_relocated(void*) API to allow the kernel relocation code to update platform's information about the DTB location if the DTB had to be moved due to being placed in a location used by the relocated kernel. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14611/ Signed-off-by: Ralf Baechle --- arch/mips/generic/init.c | 13 +++++++++++++ arch/mips/include/asm/bootinfo.h | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c index d493ccbf274a..4af619215410 100644 --- a/arch/mips/generic/init.c +++ b/arch/mips/generic/init.c @@ -88,6 +88,19 @@ void __init *plat_get_fdt(void) return (void *)fdt; } +void __init plat_fdt_relocated(void *new_location) +{ + /* + * reset fdt as the cached value would point to the location + * before relocations happened and update the location argument + * if it was passed using UHI + */ + fdt = NULL; + + if (fw_arg0 == -2) + fw_arg1 = (unsigned long)new_location; +} + void __init plat_mem_setup(void) { if (mach && mach->fixup_fdt) diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index ee9f5f2d18fc..e26a093bb17a 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -164,6 +164,19 @@ static inline void plat_swiotlb_setup(void) {} * Return: Pointer to the flattened device tree blob. */ extern void *plat_get_fdt(void); + +#ifdef CONFIG_RELOCATABLE + +/** + * plat_fdt_relocated() - Update platform's information about relocated dtb + * + * This function provides a platform-independent API to set platform's + * information about relocated DTB if it needs to be moved due to kernel + * relocation occurring at boot. + */ +void plat_fdt_relocated(void *new_location); + +#endif /* CONFIG_RELOCATABLE */ #endif /* CONFIG_USE_OF */ #endif /* _ASM_BOOTINFO_H */ From 4c9fff362261d68cc35053a76afea85f1277ac66 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:48 +0100 Subject: [PATCH 0152/1587] MIPS: relocate: Optionally relocate the DTB If the DTB is located in the target memory area for the relocated kernel it needs to be relocated as well before kernel relocation takes place. After copying the DTB use the new plat_fdt_relocated() API from the relocated kernel to ensure the relocated kernel updates any information that it may have cached about the location of the DTB. plat_fdt_relocated is declared as a weak symbol so that platforms that do not require it do not need to implement the method. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14616/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/relocate.c | 38 +++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c index c82288569eb1..9103bebc9a8e 100644 --- a/arch/mips/kernel/relocate.c +++ b/arch/mips/kernel/relocate.c @@ -31,6 +31,8 @@ extern u32 _relocation_end[]; /* End relocation table */ extern long __start___ex_table; /* Start exception table */ extern long __stop___ex_table; /* End exception table */ +extern void __weak plat_fdt_relocated(void *new_location); + /* * This function may be defined for a platform to perform any post-relocation * fixup necessary. @@ -41,7 +43,6 @@ int __weak plat_post_relocation(long offset) return 0; } - static inline u32 __init get_synci_step(void) { u32 res; @@ -302,12 +303,14 @@ void *__init relocate_kernel(void) int res = 1; /* Default to original kernel entry point */ void *kernel_entry = start_kernel; + void *fdt = NULL; /* Get the command line */ fw_init_cmdline(); #if defined(CONFIG_USE_OF) /* Deal with the device tree */ - early_init_dt_scan(plat_get_fdt()); + fdt = plat_get_fdt(); + early_init_dt_scan(fdt); if (boot_command_line[0]) { /* Boot command line was passed in device tree */ strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); @@ -327,6 +330,29 @@ void *__init relocate_kernel(void) arcs_cmdline[0] = '\0'; if (offset) { + void (*fdt_relocated_)(void *) = NULL; +#if defined(CONFIG_USE_OF) + unsigned long fdt_phys = virt_to_phys(fdt); + + /* + * If built-in dtb is used then it will have been relocated + * during kernel _text relocation. If appended DTB is used + * then it will not be relocated, but it should remain + * intact in the original location. If dtb is loaded by + * the bootloader then it may need to be moved if it crosses + * the target memory area + */ + + if (fdt_phys >= virt_to_phys(RELOCATED(&_text)) && + fdt_phys <= virt_to_phys(RELOCATED(&_end))) { + void *fdt_relocated = + RELOCATED(ALIGN((long)&_end, PAGE_SIZE)); + memcpy(fdt_relocated, fdt, fdt_totalsize(fdt)); + fdt = fdt_relocated; + fdt_relocated_ = RELOCATED(&plat_fdt_relocated); + } +#endif /* CONFIG_USE_OF */ + /* Copy the kernel to it's new location */ memcpy(loc_new, &_text, kernel_length); @@ -349,6 +375,14 @@ void *__init relocate_kernel(void) */ memcpy(RELOCATED(&__bss_start), &__bss_start, bss_length); + /* + * If fdt was stored outside of the kernel image and + * had to be moved then update platform's state data + * with the new fdt location + */ + if (fdt_relocated_) + fdt_relocated_(fdt); + /* * Last chance for the platform to abort relocation. * This may also be used by the platform to perform any From 73fbc1eba7ffa3bf0ad12486232a8a1edb4e4411 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:49 +0100 Subject: [PATCH 0153/1587] MIPS: fix mem=X@Y commandline processing When a memory offset is specified through the commandline, add the memory in range PHYS_OFFSET:Y as reserved memory area. Otherwise the bootmem allocator is initialised with low page equal to min_low_pfn = PHYS_OFFSET, and in free_all_bootmem will process pages starting from min_low_pfn instead of PFN(Y). Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14613/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index c22f0fdd4cfb..ae888662bda3 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -662,6 +662,10 @@ static int __init early_parse_mem(char *p) start = memparse(p + 1, &p); add_memory_region(start, size, BOOT_MEM_RAM); + + if (start && start > PHYS_OFFSET) + add_memory_region(PHYS_OFFSET, start - PHYS_OFFSET, + BOOT_MEM_RESERVED); return 0; } early_param("mem", early_parse_mem); From a8f108d70c74d83574c157648383eb2e4285a190 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:50 +0100 Subject: [PATCH 0154/1587] MIPS: kexec: Do not reserve invalid crashkernel memory on boot Do not reserve memory for the crashkernel if the commandline argument points to a wrong location. This can happen if the location is specified wrong or if the same commandline is reused when starting the crashkernel - in the latter case the reserved memory would point to the location from which the crashkernel is executing. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14612/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index ae888662bda3..01d1dbde5fbf 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -741,6 +741,11 @@ static void __init mips_parse_crashkernel(void) if (ret != 0 || crash_size <= 0) return; + if (!memory_region_available(crash_base, crash_size)) { + pr_warn("Invalid memory region reserved for crash kernel\n"); + return; + } + crashk_res.start = crash_base; crashk_res.end = crash_base + crash_size - 1; } From 856b0f591e951a234d6642cc466023df182eb51c Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:51 +0100 Subject: [PATCH 0155/1587] MIPS: kexec: add debug info about the new kexec'ed image Print details of the new kexec image loaded. Based on the original code from commit 221f2c770e10d ("arm64/kexec: Add pr_debug output") Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14614/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/machine_kexec.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 59725204105c..8b574bcd39ba 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -28,9 +28,31 @@ atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); void (*_crash_smp_send_stop)(void) = NULL; #endif +static void kexec_image_info(const struct kimage *kimage) +{ + unsigned long i; + + pr_debug("kexec kimage info:\n"); + pr_debug(" type: %d\n", kimage->type); + pr_debug(" start: %lx\n", kimage->start); + pr_debug(" head: %lx\n", kimage->head); + pr_debug(" nr_segments: %lu\n", kimage->nr_segments); + + for (i = 0; i < kimage->nr_segments; i++) { + pr_debug(" segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n", + i, + kimage->segment[i].mem, + kimage->segment[i].mem + kimage->segment[i].memsz, + (unsigned long)kimage->segment[i].memsz, + (unsigned long)kimage->segment[i].memsz / PAGE_SIZE); + } +} + int machine_kexec_prepare(struct kimage *kimage) { + kexec_image_info(kimage); + if (_machine_kexec_prepare) return _machine_kexec_prepare(kimage); return 0; From 0014dea6b71ae3e0384c3358f632b4728c3d432e Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Wed, 23 Nov 2016 14:43:52 +0100 Subject: [PATCH 0156/1587] MIPS: generic/kexec: add support for a DTB passed in a separate buffer Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14615/ Signed-off-by: Ralf Baechle --- arch/mips/generic/Makefile | 1 + arch/mips/generic/kexec.c | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 arch/mips/generic/kexec.c diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile index 7c66494151db..acb9b6d62b16 100644 --- a/arch/mips/generic/Makefile +++ b/arch/mips/generic/Makefile @@ -13,3 +13,4 @@ obj-y += irq.o obj-y += proc.o obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o +obj-$(CONFIG_KEXEC) += kexec.o diff --git a/arch/mips/generic/kexec.c b/arch/mips/generic/kexec.c new file mode 100644 index 000000000000..e9fb735299e3 --- /dev/null +++ b/arch/mips/generic/kexec.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Marcin Nowakowski + * + * 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 + +static int generic_kexec_prepare(struct kimage *image) +{ + int i; + + for (i = 0; i < image->nr_segments; i++) { + struct fdt_header fdt; + + if (image->segment[i].memsz <= sizeof(fdt)) + continue; + + if (copy_from_user(&fdt, image->segment[i].buf, sizeof(fdt))) + continue; + + if (fdt_check_header(&fdt)) + continue; + + kexec_args[0] = -2; + kexec_args[1] = (unsigned long) + phys_to_virt((unsigned long)image->segment[i].mem); + break; + } + return 0; +} + +static int __init register_generic_kexec(void) +{ + _machine_kexec_prepare = generic_kexec_prepare; + return 0; +} +arch_initcall(register_generic_kexec); From ef462f3b64e9fb0c8e1cd5d60f5bd7f13ac2156d Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 7 Dec 2016 17:16:26 -0800 Subject: [PATCH 0157/1587] MIPS: Add cacheinfo support Add cacheinfo support for MIPS architectures. Use information from the cpuinfo_mips struct to populate the cacheinfo struct. This allows an architecture agnostic approach, however this also means if cache information is not properly populated within the cpuinfo_mips struct, there is nothing we can do. (I.E. c-r3k.c) Signed-off-by: Justin Chen Cc: f.fainelli@gmail.com Cc: linux-mips@linux-mips.org Cc: bcm-kernel-feedback-list@broadcom.com Patchwork: https://patchwork.linux-mips.org/patch/14650/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 2 +- arch/mips/kernel/cacheinfo.c | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 arch/mips/kernel/cacheinfo.c diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 4a603a3ea657..904a9c48553a 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := head.o vmlinux.lds obj-y += cpu-probe.o branch.o elf.o entry.o genex.o idle.o irq.o \ process.o prom.o ptrace.o reset.o setup.o signal.o \ syscall.o time.o topology.o traps.o unaligned.o watch.o \ - vdso.o + vdso.o cacheinfo.o ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_ftrace.o = -pg diff --git a/arch/mips/kernel/cacheinfo.c b/arch/mips/kernel/cacheinfo.c new file mode 100644 index 000000000000..a92bbbae969b --- /dev/null +++ b/arch/mips/kernel/cacheinfo.c @@ -0,0 +1,85 @@ +/* + * MIPS cacheinfo support + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +/* Populates leaf and increments to next leaf */ +#define populate_cache(cache, leaf, c_level, c_type) \ + leaf->type = c_type; \ + leaf->level = c_level; \ + leaf->coherency_line_size = c->cache.linesz; \ + leaf->number_of_sets = c->cache.sets; \ + leaf->ways_of_associativity = c->cache.ways; \ + leaf->size = c->cache.linesz * c->cache.sets * \ + c->cache.ways; \ + leaf++; + +static int __init_cache_level(unsigned int cpu) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + int levels = 0, leaves = 0; + + /* + * If Dcache is not set, we assume the cache structures + * are not properly initialized. + */ + if (c->dcache.waysize) + levels += 1; + else + return -ENOENT; + + + leaves += (c->icache.waysize) ? 2 : 1; + + if (c->scache.waysize) { + levels++; + leaves++; + } + + if (c->tcache.waysize) { + levels++; + leaves++; + } + + this_cpu_ci->num_levels = levels; + this_cpu_ci->num_leaves = leaves; + return 0; +} + +static int __populate_cache_leaves(unsigned int cpu) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf = this_cpu_ci->info_list; + + if (c->icache.waysize) { + populate_cache(dcache, this_leaf, 1, CACHE_TYPE_DATA); + populate_cache(icache, this_leaf, 1, CACHE_TYPE_INST); + } else { + populate_cache(dcache, this_leaf, 1, CACHE_TYPE_UNIFIED); + } + + if (c->scache.waysize) + populate_cache(scache, this_leaf, 2, CACHE_TYPE_UNIFIED); + + if (c->tcache.waysize) + populate_cache(tcache, this_leaf, 3, CACHE_TYPE_UNIFIED); + + return 0; +} + +DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level) +DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves) From 4f79ddec04229c966326d90cc3cfd414401dea22 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:12:40 +0100 Subject: [PATCH 0158/1587] MIPS: ralink: MT7621 does not set its SoC type. The code does not set the SoC type properly. This went unnoticed until now as the SoC does not share any of the driver code with the other SoCs, until we made the mmc driver work. Signed-off-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14896/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/mt7621.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c index a45bbbe97ac5..3ffa4ba78131 100644 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c @@ -181,7 +181,7 @@ void prom_soc_init(struct ralink_soc_info *soc_info) } else { panic("mt7621: unknown SoC, n0:%08x n1:%08x\n", n0, n1); } - + ralink_soc = MT762X_SOC_MT7621AT; rev = __raw_readl(sysc + SYSC_REG_CHIP_REV); snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, From 2517caf19dbfac3b39f2db5500c5fd03c4370e81 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:12:41 +0100 Subject: [PATCH 0159/1587] MIPS: ralink: Add missing I2C and I2S clocks. This patch adds two additional clocks required by the audio interface of the SoCs. Signed-off-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14897/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/mt7620.c | 5 +++++ arch/mips/ralink/rt288x.c | 1 + arch/mips/ralink/rt305x.c | 2 ++ arch/mips/ralink/rt3883.c | 2 ++ 4 files changed, 10 insertions(+) diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 3c7c9bf57bf3..6f0fdfd1e32a 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -509,6 +509,7 @@ void __init ralink_clk_init(void) unsigned long sys_rate; unsigned long dram_rate; unsigned long periph_rate; + unsigned long pcmi2s_rate; xtal_rate = mt7620_get_xtal_rate(); @@ -523,6 +524,7 @@ void __init ralink_clk_init(void) cpu_rate = MHZ(575); dram_rate = sys_rate = cpu_rate / 3; periph_rate = MHZ(40); + pcmi2s_rate = MHZ(480); ralink_clk_add("10000d00.uartlite", periph_rate); ralink_clk_add("10000e00.uartlite", periph_rate); @@ -534,6 +536,7 @@ void __init ralink_clk_init(void) dram_rate = mt7620_get_dram_rate(pll_rate); sys_rate = mt7620_get_sys_rate(cpu_rate); periph_rate = mt7620_get_periph_rate(xtal_rate); + pcmi2s_rate = periph_rate; pr_debug(RFMT("XTAL") RFMT("CPU_PLL") RFMT("PLL"), RINT(xtal_rate), RFRAC(xtal_rate), @@ -555,6 +558,8 @@ void __init ralink_clk_init(void) ralink_clk_add("cpu", cpu_rate); ralink_clk_add("10000100.timer", periph_rate); ralink_clk_add("10000120.watchdog", periph_rate); + ralink_clk_add("10000900.i2c", periph_rate); + ralink_clk_add("10000a00.i2s", pcmi2s_rate); ralink_clk_add("10000b00.spi", sys_rate); ralink_clk_add("10000b40.spi", sys_rate); ralink_clk_add("10000c00.uartlite", periph_rate); diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index 285796e6d75c..eeabd5119891 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -75,6 +75,7 @@ void __init ralink_clk_init(void) ralink_clk_add("300100.timer", cpu_rate / 2); ralink_clk_add("300120.watchdog", cpu_rate / 2); ralink_clk_add("300500.uart", cpu_rate / 2); + ralink_clk_add("300900.i2c", cpu_rate / 2); ralink_clk_add("300c00.uartlite", cpu_rate / 2); ralink_clk_add("400000.ethernet", cpu_rate / 2); ralink_clk_add("480000.wmac", wmac_rate); diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index c8a28c4bf29e..f0b5ac444556 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -200,6 +200,8 @@ void __init ralink_clk_init(void) ralink_clk_add("cpu", cpu_rate); ralink_clk_add("sys", sys_rate); + ralink_clk_add("10000900.i2c", uart_rate); + ralink_clk_add("10000a00.i2s", uart_rate); ralink_clk_add("10000b00.spi", sys_rate); ralink_clk_add("10000b40.spi", sys_rate); ralink_clk_add("10000100.timer", wdt_rate); diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index 4cef9162bd9b..141c597ec324 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -108,6 +108,8 @@ void __init ralink_clk_init(void) ralink_clk_add("10000100.timer", sys_rate); ralink_clk_add("10000120.watchdog", sys_rate); ralink_clk_add("10000500.uart", 40000000); + ralink_clk_add("10000900.i2c", 40000000); + ralink_clk_add("10000a00.i2s", 40000000); ralink_clk_add("10000b00.spi", sys_rate); ralink_clk_add("10000b40.spi", sys_rate); ralink_clk_add("10000c00.uartlite", 40000000); From 16eccef68f21b729d18573a36eef41053a5f35bd Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:12:42 +0100 Subject: [PATCH 0160/1587] MIPS: ralink: Add missing pinmux. The mt7620 has a pin that can be used to generate an external reference clock. The pinmux setup was missing the definition of said pin. This patch adds it. Signed-off-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14898/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-ralink/mt7620.h | 7 ++++++- arch/mips/ralink/mt7620.c | 8 ++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h index a73350b07fdf..66af4ccb5c6c 100644 --- a/arch/mips/include/asm/mach-ralink/mt7620.h +++ b/arch/mips/include/asm/mach-ralink/mt7620.h @@ -115,9 +115,14 @@ #define MT7620_GPIO_MODE_WDT_MASK 0x3 #define MT7620_GPIO_MODE_WDT_SHIFT 21 +#define MT7620_GPIO_MODE_MDIO 0 +#define MT7620_GPIO_MODE_MDIO_REFCLK 1 +#define MT7620_GPIO_MODE_MDIO_GPIO 2 +#define MT7620_GPIO_MODE_MDIO_MASK 0x3 +#define MT7620_GPIO_MODE_MDIO_SHIFT 7 + #define MT7620_GPIO_MODE_I2C 0 #define MT7620_GPIO_MODE_UART1 5 -#define MT7620_GPIO_MODE_MDIO 8 #define MT7620_GPIO_MODE_RGMII1 9 #define MT7620_GPIO_MODE_RGMII2 10 #define MT7620_GPIO_MODE_SPI 11 diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 6f0fdfd1e32a..2503878824b8 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -55,7 +55,10 @@ static int dram_type; static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; static struct rt2880_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; static struct rt2880_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; -static struct rt2880_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func mdio_grp[] = { + FUNC("mdio", MT7620_GPIO_MODE_MDIO, 22, 2), + FUNC("refclk", MT7620_GPIO_MODE_MDIO_REFCLK, 22, 2), +}; static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) }; static struct rt2880_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) }; static struct rt2880_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) }; @@ -92,7 +95,8 @@ static struct rt2880_pmx_group mt7620a_pinmux_data[] = { GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1), GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK, MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT), - GRP("mdio", mdio_grp, 1, MT7620_GPIO_MODE_MDIO), + GRP_G("mdio", mdio_grp, MT7620_GPIO_MODE_MDIO_MASK, + MT7620_GPIO_MODE_MDIO_GPIO, MT7620_GPIO_MODE_MDIO_SHIFT), GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1), GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK), GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK, From 58181a117d353427127a2e7afc7cf1ab44759828 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:12:43 +0100 Subject: [PATCH 0161/1587] MIPS: ralink: Fix a typo in the pinmux setup. There is a typo inside the pinmux setup code. The function is really called utif and not util. This was recently discovered when people were trying to make the UTIF interface work. Signed-off-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14899/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/mt7620.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 2503878824b8..76416b487564 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -180,7 +180,7 @@ static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = { static struct rt2880_pmx_func spis_grp_mt7628[] = { FUNC("pwm_uart2", 3, 14, 4), - FUNC("util", 2, 14, 4), + FUNC("utif", 2, 14, 4), FUNC("gpio", 1, 14, 4), FUNC("spis", 0, 14, 4), }; @@ -194,28 +194,28 @@ static struct rt2880_pmx_func gpio_grp_mt7628[] = { static struct rt2880_pmx_func p4led_kn_grp_mt7628[] = { FUNC("jtag", 3, 30, 1), - FUNC("util", 2, 30, 1), + FUNC("utif", 2, 30, 1), FUNC("gpio", 1, 30, 1), FUNC("p4led_kn", 0, 30, 1), }; static struct rt2880_pmx_func p3led_kn_grp_mt7628[] = { FUNC("jtag", 3, 31, 1), - FUNC("util", 2, 31, 1), + FUNC("utif", 2, 31, 1), FUNC("gpio", 1, 31, 1), FUNC("p3led_kn", 0, 31, 1), }; static struct rt2880_pmx_func p2led_kn_grp_mt7628[] = { FUNC("jtag", 3, 32, 1), - FUNC("util", 2, 32, 1), + FUNC("utif", 2, 32, 1), FUNC("gpio", 1, 32, 1), FUNC("p2led_kn", 0, 32, 1), }; static struct rt2880_pmx_func p1led_kn_grp_mt7628[] = { FUNC("jtag", 3, 33, 1), - FUNC("util", 2, 33, 1), + FUNC("utif", 2, 33, 1), FUNC("gpio", 1, 33, 1), FUNC("p1led_kn", 0, 33, 1), }; @@ -236,28 +236,28 @@ static struct rt2880_pmx_func wled_kn_grp_mt7628[] = { static struct rt2880_pmx_func p4led_an_grp_mt7628[] = { FUNC("jtag", 3, 39, 1), - FUNC("util", 2, 39, 1), + FUNC("utif", 2, 39, 1), FUNC("gpio", 1, 39, 1), FUNC("p4led_an", 0, 39, 1), }; static struct rt2880_pmx_func p3led_an_grp_mt7628[] = { FUNC("jtag", 3, 40, 1), - FUNC("util", 2, 40, 1), + FUNC("utif", 2, 40, 1), FUNC("gpio", 1, 40, 1), FUNC("p3led_an", 0, 40, 1), }; static struct rt2880_pmx_func p2led_an_grp_mt7628[] = { FUNC("jtag", 3, 41, 1), - FUNC("util", 2, 41, 1), + FUNC("utif", 2, 41, 1), FUNC("gpio", 1, 41, 1), FUNC("p2led_an", 0, 41, 1), }; static struct rt2880_pmx_func p1led_an_grp_mt7628[] = { FUNC("jtag", 3, 42, 1), - FUNC("util", 2, 42, 1), + FUNC("utif", 2, 42, 1), FUNC("gpio", 1, 42, 1), FUNC("p1led_an", 0, 42, 1), }; From 80e6321abc859955331c78c93e442e72b942c5c1 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:12:44 +0100 Subject: [PATCH 0162/1587] MIPS: ralink: Add missing clk_round_rate(). As we dont use the common clock api yet we need to add this stub to allow building drivers that use the API. Signed-off-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14900/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/clk.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c index ebaa7cc0e995..64c3db5e8e8a 100644 --- a/arch/mips/ralink/clk.c +++ b/arch/mips/ralink/clk.c @@ -62,6 +62,12 @@ int clk_set_rate(struct clk *clk, unsigned long rate) } EXPORT_SYMBOL_GPL(clk_set_rate); +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return -1; +} +EXPORT_SYMBOL_GPL(clk_round_rate); + void __init plat_time_init(void) { struct clk *clk; From 07724712bf22aec5fe44e5d399f115755f436721 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:12:45 +0100 Subject: [PATCH 0163/1587] MIPS: ralink: Add missing symbol for highmem support. MT7621 has highmem. this was previously not working as the required symbol was not selected in the Kconfig file. Signed-off-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14901/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 813826a456ca..9825dee10bc1 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -46,6 +46,7 @@ choice select SYS_SUPPORTS_MULTITHREADING select SYS_SUPPORTS_SMP select SYS_SUPPORTS_MIPS_CPS + select SYS_SUPPORTS_HIGHMEM select MIPS_GIC select COMMON_CLK select CLKSRC_MIPS_GIC From 9c48568b3692f1a56cbf1935e4eea835e6b185b1 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:12:46 +0100 Subject: [PATCH 0164/1587] MIPS: ralink: Cosmetic change to prom_init(). Over the years the code has been changed various times leading to argc/argv being defined in a different function to where we actually use the variables. Clean this up by moving them to prom_init_cmdline(). Signed-off-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14902/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/prom.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c index 5a73c5e14221..23198c9050e5 100644 --- a/arch/mips/ralink/prom.c +++ b/arch/mips/ralink/prom.c @@ -30,8 +30,10 @@ const char *get_system_type(void) return soc_info.sys_type; } -static __init void prom_init_cmdline(int argc, char **argv) +static __init void prom_init_cmdline(void) { + int argc; + char **argv; int i; pr_debug("prom: fw_arg0=%08x fw_arg1=%08x fw_arg2=%08x fw_arg3=%08x\n", @@ -60,14 +62,11 @@ static __init void prom_init_cmdline(int argc, char **argv) void __init prom_init(void) { - int argc; - char **argv; - prom_soc_init(&soc_info); pr_info("SoC Type: %s\n", get_system_type()); - prom_init_cmdline(argc, argv); + prom_init_cmdline(); } void __init prom_free_prom_memory(void) From cd854fc6f18f0c231f11f2c42167a07e3b265c72 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Tue, 13 Dec 2016 10:48:30 +0100 Subject: [PATCH 0165/1587] MIPS: uprobes: Remove __weak attribute from arch_uprobe_copy_ixol. Arch-specific implementation of arch_uprobe_copy_ixol is expected to override the weak implementation in generic code. As currently both implementations are marked as weak, it is up to the linker to chose one. Remove the __weak attribute from MIPS code to make sure the correct version is used. Fixes: 40e084a506eb ("MIPS: Add uprobes support.") Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14660/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/uprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c index dbb917403131..e99e3fae5326 100644 --- a/arch/mips/kernel/uprobes.c +++ b/arch/mips/kernel/uprobes.c @@ -226,7 +226,7 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN); } -void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, +void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, void *src, unsigned long len) { unsigned long kaddr, kstart; From 5c01918068ecc673dcea265e71ad95f949f28e2d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 21 Dec 2016 03:32:50 +0100 Subject: [PATCH 0166/1587] MIPS: IRQ: Remove useless i8259_of_init() prototype. Signed-off-by: Ralf Baechle --- arch/mips/include/asm/i8259.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/include/asm/i8259.h b/arch/mips/include/asm/i8259.h index 32229c77906a..47543d56438a 100644 --- a/arch/mips/include/asm/i8259.h +++ b/arch/mips/include/asm/i8259.h @@ -40,7 +40,6 @@ extern raw_spinlock_t i8259A_lock; extern void make_8259A_irq(unsigned int irq); extern void init_i8259_irqs(void); -extern int i8259_of_init(struct device_node *node, struct device_node *parent); /** * i8159_set_poll() - Override the i8259 polling function From de96ec2a77c6d06a423c2c495bb4a2f4299f3d9e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 23 Sep 2016 16:38:27 +0100 Subject: [PATCH 0167/1587] OF: Prevent unaligned access in of_alias_scan() When allocating a struct alias_prop, of_alias_scan() only requested that it be aligned on a 4 byte boundary. The struct contains pointers which leads to us attempting 64 bit writes on 64 bit systems, and if the CPU doesn't support unaligned memory accesses then this causes problems - for example on some MIPS64r2 CPUs including the "mips64r2-generic" QEMU emulated CPU it will trigger an address error exception. Fix this by requesting alignment for the struct alias_prop allocation matching that which the compiler expects, using the __alignof__ keyword. Signed-off-by: Paul Burton Acked-by: Rob Herring Reviewed-by: Grant Likely Cc: Frank Rowand Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14306/ Signed-off-by: Ralf Baechle --- drivers/of/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index d4bea3c797d6..84cf2f3f396c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2112,7 +2112,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) continue; /* Allocate an alias_prop with enough space for the stem */ - ap = dt_alloc(sizeof(*ap) + len + 1, 4); + ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap)); if (!ap) continue; memset(ap, 0, sizeof(*ap) + len + 1); From 858e2b2310cac0dff1df8eea7d16b6ad7ef2c2b5 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:07 +0000 Subject: [PATCH 0168/1587] MIPS: Use generic asm/export.h Include export.h in the list of generic headers used by the MIPS architecture for use by later patches. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14506/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/Kbuild | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index 45b0d6568270..ed07179fe26a 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -5,6 +5,7 @@ generic-y += cputime.h generic-y += current.h generic-y += dma-contiguous.h generic-y += emergency-restart.h +generic-y += export.h generic-y += irq_work.h generic-y += local64.h generic-y += mcs_spinlock.h From 2c0e57eaef3c2b233e42faf4e9db18ee8fd37734 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:08 +0000 Subject: [PATCH 0169/1587] MIPS: tlbex: Clear ISA bit when writing to handle_tlb{l,m,s} When generating TLB exception handling code we write to memory reserved at the handle_tlbl, handle_tlbm & handle_tlbs symbols. Up until now the ISA bit has always been clear simply because the assembly code reserving the space for those functions places no instructions in them. In preparation for marking all LEAF functions as containing code, explicitly clear the ISA bit when calculating the addresses at which to write TLB exception handling code. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14507/ Signed-off-by: Ralf Baechle --- arch/mips/mm/tlbex.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 55ce39606cb8..87eed65660f5 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -2041,7 +2041,7 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l, static void build_r4000_tlb_load_handler(void) { - u32 *p = handle_tlbl; + u32 *p = (u32 *)msk_isa16_mode((ulong)handle_tlbl); const int handle_tlbl_size = handle_tlbl_end - handle_tlbl; struct uasm_label *l = labels; struct uasm_reloc *r = relocs; @@ -2224,7 +2224,7 @@ static void build_r4000_tlb_load_handler(void) static void build_r4000_tlb_store_handler(void) { - u32 *p = handle_tlbs; + u32 *p = (u32 *)msk_isa16_mode((ulong)handle_tlbs); const int handle_tlbs_size = handle_tlbs_end - handle_tlbs; struct uasm_label *l = labels; struct uasm_reloc *r = relocs; @@ -2279,7 +2279,7 @@ static void build_r4000_tlb_store_handler(void) static void build_r4000_tlb_modify_handler(void) { - u32 *p = handle_tlbm; + u32 *p = (u32 *)msk_isa16_mode((ulong)handle_tlbm); const int handle_tlbm_size = handle_tlbm_end - handle_tlbm; struct uasm_label *l = labels; struct uasm_reloc *r = relocs; From 08889582b8aa0bbc01a1e5a0033b9f98d2e11caa Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:09 +0000 Subject: [PATCH 0170/1587] MIPS: End asm function prologue macros with .insn When building a kernel targeting a microMIPS ISA, recent GNU linkers will fail the link if they cannot determine that the target of a branch or jump is microMIPS code, with errors such as the following: mips-img-linux-gnu-ld: arch/mips/built-in.o: .text+0x542c: Unsupported jump between ISA modes; consider recompiling with interlinking enabled. mips-img-linux-gnu-ld: final link failed: Bad value or: ./arch/mips/include/asm/uaccess.h:1017: warning: JALX to a non-word-aligned address Placing anything other than an instruction at the start of a function written in assembly appears to trigger such errors. In order to prepare for allowing us to follow function prologue macros with an EXPORT_SYMBOL invocation, end the prologue macros (LEAD, NESTED & FEXPORT) with a .insn directive. This ensures that the start of the function is marked as code, which always makes sense for functions & safely prevents us from hitting the link errors described above. Signed-off-by: Paul Burton Reviewed-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14508/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/asm.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 7c26b28bf252..859cf7048347 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -54,7 +54,8 @@ .align 2; \ .type symbol, @function; \ .ent symbol, 0; \ -symbol: .frame sp, 0, ra +symbol: .frame sp, 0, ra; \ + .insn /* * NESTED - declare nested routine entry point @@ -63,8 +64,9 @@ symbol: .frame sp, 0, ra .globl symbol; \ .align 2; \ .type symbol, @function; \ - .ent symbol, 0; \ -symbol: .frame sp, framesize, rpc + .ent symbol, 0; \ +symbol: .frame sp, framesize, rpc; \ + .insn /* * END - mark end of function @@ -86,7 +88,7 @@ symbol: #define FEXPORT(symbol) \ .globl symbol; \ .type symbol, @function; \ -symbol: +symbol: .insn /* * ABS - export absolute symbol From 29830c124d834c4ce0133aaf8ca85f045f9e758c Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:10 +0000 Subject: [PATCH 0171/1587] MIPS: Export _save_fp & _save_msa alongside their definitions Now that EXPORT_SYMBOL can be used from assembly source, move the EXPORT_SYMBOL invocations for _save_fp & _save_msa to be alongside their definitions. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14509/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips_ksyms.c | 8 -------- arch/mips/kernel/r2300_switch.S | 2 ++ arch/mips/kernel/r4k_switch.S | 3 +++ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 93aeec705a6e..a7aca7b8097d 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -34,14 +34,6 @@ extern long __strnlen_kernel_asm(const char *s); extern long __strnlen_user_nocheck_asm(const char *s); extern long __strnlen_user_asm(const char *s); -/* - * Core architecture code - */ -EXPORT_SYMBOL_GPL(_save_fp); -#ifdef CONFIG_CPU_HAS_MSA -EXPORT_SYMBOL_GPL(_save_msa); -#endif - /* * String functions */ diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index ac27ef7d4d0e..1049eeafd97d 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include @@ -72,6 +73,7 @@ LEAF(resume) * Save a thread's fp context. */ LEAF(_save_fp) +EXPORT_SYMBOL(_save_fp) fpu_save_single a0, t1 # clobbers t1 jr ra END(_save_fp) diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 2f0a3b223c97..758577861523 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include @@ -75,6 +76,7 @@ * Save a thread's fp context. */ LEAF(_save_fp) +EXPORT_SYMBOL(_save_fp) #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ defined(CONFIG_CPU_MIPS32_R6) mfc0 t0, CP0_STATUS @@ -101,6 +103,7 @@ LEAF(_restore_fp) * Save a thread's MSA vector context. */ LEAF(_save_msa) +EXPORT_SYMBOL(_save_msa) msa_save_all a0 jr ra END(_save_msa) From 827456e71036681039e2c89f58e29f950ef3eb05 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:48:04 +0000 Subject: [PATCH 0172/1587] MIPS: Export _mcount alongside its definition Now that EXPORT_SYMBOL can be used from assembly source, move the EXPORT_SYMBOL invocation for _mcount to be alongside its definition. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14525/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mcount.S | 3 +++ arch/mips/kernel/mips_ksyms.c | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 2f7c734771f4..f2ee7e1e3342 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -10,6 +10,7 @@ * Author: Wu Zhangjin */ +#include #include #include #include @@ -66,6 +67,7 @@ NESTED(ftrace_caller, PT_SIZE, ra) .globl _mcount _mcount: +EXPORT_SYMBOL(_mcount) b ftrace_stub #ifdef CONFIG_32BIT addiu sp,sp,8 @@ -114,6 +116,7 @@ ftrace_stub: #else /* ! CONFIG_DYNAMIC_FTRACE */ NESTED(_mcount, PT_SIZE, ra) +EXPORT_SYMBOL(_mcount) PTR_LA t1, ftrace_stub PTR_L t2, ftrace_trace_function /* Prepare t2 for (1) */ bne t1, t2, static_trace diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index a7aca7b8097d..02d8ce125c12 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -80,7 +80,3 @@ EXPORT_SYMBOL(__csum_partial_copy_from_user); #endif EXPORT_SYMBOL(invalid_pte_table); -#ifdef CONFIG_FUNCTION_TRACER -/* _mcount is defined in arch/mips/kernel/mcount.S */ -EXPORT_SYMBOL(_mcount); -#endif From aa4089e6ce54b5a7aaf5a0e8afb442395cca8503 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:12 +0000 Subject: [PATCH 0173/1587] MIPS: Export invalid_pte_table alongside its definition It's unclear to me why this wasn't always the case, but move the EXPORT_SYMBOL invocation for invalid_pte_table to be alongside its definition. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14511/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips_ksyms.c | 2 -- arch/mips/mm/init.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 02d8ce125c12..c284cb76f500 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -78,5 +78,3 @@ EXPORT_SYMBOL(__csum_partial_copy_kernel); EXPORT_SYMBOL(__csum_partial_copy_to_user); EXPORT_SYMBOL(__csum_partial_copy_from_user); #endif - -EXPORT_SYMBOL(invalid_pte_table); diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index e86ebcf5c071..9d1d54b8e1e8 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -540,3 +541,4 @@ pgd_t swapper_pg_dir[_PTRS_PER_PGD] __section(.bss..swapper_pg_dir); pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned_bss; #endif pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss; +EXPORT_SYMBOL(invalid_pte_table); From 231300423a5486cbd9e102d741190428b2783ab2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:13 +0000 Subject: [PATCH 0174/1587] MIPS: Export csum functions alongside their definitions Now that EXPORT_SYMBOL can be used from assembly source, move the EXPORT_SYMBOL invocations for the csum_partial_* functions to be alongside their definitions. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14512/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips_ksyms.c | 8 -------- arch/mips/lib/csum_partial.S | 6 ++++++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index c284cb76f500..d6973f450288 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -70,11 +70,3 @@ EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm); EXPORT_SYMBOL(__strnlen_kernel_asm); EXPORT_SYMBOL(__strnlen_user_nocheck_asm); EXPORT_SYMBOL(__strnlen_user_asm); - -#ifndef CONFIG_CPU_MIPSR6 -EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(csum_partial_copy_nocheck); -EXPORT_SYMBOL(__csum_partial_copy_kernel); -EXPORT_SYMBOL(__csum_partial_copy_to_user); -EXPORT_SYMBOL(__csum_partial_copy_from_user); -#endif diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S index ed88647b57e2..2ff84f4b1717 100644 --- a/arch/mips/lib/csum_partial.S +++ b/arch/mips/lib/csum_partial.S @@ -13,6 +13,7 @@ #include #include #include +#include #include #ifdef CONFIG_64BIT @@ -103,6 +104,7 @@ .set noreorder .align 5 LEAF(csum_partial) +EXPORT_SYMBOL(csum_partial) move sum, zero move t7, zero @@ -460,6 +462,7 @@ LEAF(csum_partial) #endif .if \__nocheck == 1 FEXPORT(csum_partial_copy_nocheck) + EXPORT_SYMBOL(csum_partial_copy_nocheck) .endif move sum, zero move odd, zero @@ -823,9 +826,12 @@ LEAF(csum_partial) .endm LEAF(__csum_partial_copy_kernel) +EXPORT_SYMBOL(__csum_partial_copy_kernel) #ifndef CONFIG_EVA FEXPORT(__csum_partial_copy_to_user) +EXPORT_SYMBOL(__csum_partial_copy_to_user) FEXPORT(__csum_partial_copy_from_user) +EXPORT_SYMBOL(__csum_partial_copy_from_user) #endif __BUILD_CSUM_PARTIAL_COPY_USER LEGACY_MODE USEROP USEROP 1 END(__csum_partial_copy_kernel) From d6cb671589757ec3d20e5e0886505cdad327b1b3 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:14 +0000 Subject: [PATCH 0175/1587] MIPS: Export string functions alongside their definitions Now that EXPORT_SYMBOL can be used from assembly source, move the EXPORT_SYMBOL invocations for the strlen*, strnlen* & strncpy* functions to be alongside their definitions. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14513/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips_ksyms.c | 24 ------------------------ arch/mips/lib/strlen_user.S | 2 ++ arch/mips/lib/strncpy_user.S | 5 +++++ arch/mips/lib/strnlen_user.S | 3 +++ 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index d6973f450288..a84f75088247 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -19,20 +19,6 @@ extern void *__bzero_kernel(void *__s, size_t __count); extern void *__bzero(void *__s, size_t __count); -extern long __strncpy_from_kernel_nocheck_asm(char *__to, - const char *__from, long __len); -extern long __strncpy_from_kernel_asm(char *__to, const char *__from, - long __len); -extern long __strncpy_from_user_nocheck_asm(char *__to, - const char *__from, long __len); -extern long __strncpy_from_user_asm(char *__to, const char *__from, - long __len); -extern long __strlen_kernel_asm(const char *s); -extern long __strlen_user_asm(const char *s); -extern long __strnlen_kernel_nocheck_asm(const char *s); -extern long __strnlen_kernel_asm(const char *s); -extern long __strnlen_user_nocheck_asm(const char *s); -extern long __strnlen_user_asm(const char *s); /* * String functions @@ -60,13 +46,3 @@ EXPORT_SYMBOL(__copy_user_inatomic_eva); EXPORT_SYMBOL(__bzero_kernel); #endif EXPORT_SYMBOL(__bzero); -EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm); -EXPORT_SYMBOL(__strncpy_from_kernel_asm); -EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm); -EXPORT_SYMBOL(__strncpy_from_user_asm); -EXPORT_SYMBOL(__strlen_kernel_asm); -EXPORT_SYMBOL(__strlen_user_asm); -EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm); -EXPORT_SYMBOL(__strnlen_kernel_asm); -EXPORT_SYMBOL(__strnlen_user_nocheck_asm); -EXPORT_SYMBOL(__strnlen_user_asm); diff --git a/arch/mips/lib/strlen_user.S b/arch/mips/lib/strlen_user.S index 929bbacd697e..c9cb7e6c59a6 100644 --- a/arch/mips/lib/strlen_user.S +++ b/arch/mips/lib/strlen_user.S @@ -9,6 +9,7 @@ */ #include #include +#include #include #define EX(insn,reg,addr,handler) \ @@ -24,6 +25,7 @@ */ .macro __BUILD_STRLEN_ASM func LEAF(__strlen_\func\()_asm) +EXPORT_SYMBOL(__strlen_\func\()_asm) LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok? and v0, a0 bnez v0, .Lfault\@ diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S index 3c32baf8b494..af745b1d04e3 100644 --- a/arch/mips/lib/strncpy_user.S +++ b/arch/mips/lib/strncpy_user.S @@ -9,6 +9,7 @@ #include #include #include +#include #include #define EX(insn,reg,addr,handler) \ @@ -30,11 +31,13 @@ .macro __BUILD_STRNCPY_ASM func LEAF(__strncpy_from_\func\()_asm) +EXPORT_SYMBOL(__strncpy_from_\func\()_asm) LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok? and v0, a1 bnez v0, .Lfault\@ FEXPORT(__strncpy_from_\func\()_nocheck_asm) +EXPORT_SYMBOL(__strncpy_from_\func\()_nocheck_asm) move t0, zero move v1, a1 .ifeqs "\func","kernel" @@ -72,6 +75,8 @@ FEXPORT(__strncpy_from_\func\()_nocheck_asm) .global __strncpy_from_user_nocheck_asm .set __strncpy_from_user_asm, __strncpy_from_kernel_asm .set __strncpy_from_user_nocheck_asm, __strncpy_from_kernel_nocheck_asm + EXPORT_SYMBOL(__strncpy_from_user_asm) + EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm) #endif __BUILD_STRNCPY_ASM kernel diff --git a/arch/mips/lib/strnlen_user.S b/arch/mips/lib/strnlen_user.S index 77e64942f004..3ac38162d7f0 100644 --- a/arch/mips/lib/strnlen_user.S +++ b/arch/mips/lib/strnlen_user.S @@ -8,6 +8,7 @@ */ #include #include +#include #include #define EX(insn,reg,addr,handler) \ @@ -27,11 +28,13 @@ */ .macro __BUILD_STRNLEN_ASM func LEAF(__strnlen_\func\()_asm) +EXPORT_SYMBOL(__strnlen_\func\()_asm) LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok? and v0, a0 bnez v0, .Lfault\@ FEXPORT(__strnlen_\func\()_nocheck_asm) +EXPORT_SYMBOL(__strnlen_\func\()_nocheck_asm) move v0, a0 PTR_ADDU a1, a0 # stop pointer 1: From 576a2f0c5c6d64648d2ba68a4edbbe61863e12e2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:15 +0000 Subject: [PATCH 0176/1587] MIPS: Export memcpy & memset functions alongside their definitions Now that EXPORT_SYMBOL can be used from assembly source, move the EXPORT_SYMBOL invocations for the memcpy & memset functions & variants thereof to be alongside their definitions. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14514/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/octeon-memcpy.S | 5 +++++ arch/mips/kernel/mips_ksyms.c | 24 ------------------------ arch/mips/lib/memcpy.S | 9 +++++++++ arch/mips/lib/memset.S | 5 +++++ 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S index 64e08df51d65..7d96d9c72c74 100644 --- a/arch/mips/cavium-octeon/octeon-memcpy.S +++ b/arch/mips/cavium-octeon/octeon-memcpy.S @@ -15,6 +15,7 @@ #include #include +#include #include #define dst a0 @@ -142,6 +143,7 @@ * t7 is used as a flag to note inatomic mode. */ LEAF(__copy_user_inatomic) +EXPORT_SYMBOL(__copy_user_inatomic) b __copy_user_common li t7, 1 END(__copy_user_inatomic) @@ -154,9 +156,11 @@ LEAF(__copy_user_inatomic) */ .align 5 LEAF(memcpy) /* a0=dst a1=src a2=len */ +EXPORT_SYMBOL(memcpy) move v0, dst /* return value */ __memcpy: FEXPORT(__copy_user) +EXPORT_SYMBOL(__copy_user) li t7, 0 /* not inatomic */ __copy_user_common: /* @@ -459,6 +463,7 @@ s_exc: .align 5 LEAF(memmove) +EXPORT_SYMBOL(memmove) ADD t0, a0, a2 ADD t1, a1, a2 sltu t0, a1, t0 # dst + len <= src -> memcpy diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index a84f75088247..f01838faae2b 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -17,32 +17,8 @@ #include #include -extern void *__bzero_kernel(void *__s, size_t __count); -extern void *__bzero(void *__s, size_t __count); - -/* - * String functions - */ -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memmove); - /* * Functions that operate on entire pages. Mostly used by memory management. */ EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(copy_page); - -/* - * Userspace access stuff. - */ -EXPORT_SYMBOL(__copy_user); -EXPORT_SYMBOL(__copy_user_inatomic); -#ifdef CONFIG_EVA -EXPORT_SYMBOL(__copy_from_user_eva); -EXPORT_SYMBOL(__copy_in_user_eva); -EXPORT_SYMBOL(__copy_to_user_eva); -EXPORT_SYMBOL(__copy_user_inatomic_eva); -EXPORT_SYMBOL(__bzero_kernel); -#endif -EXPORT_SYMBOL(__bzero); diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S index 6c303a94a196..c3031f18c572 100644 --- a/arch/mips/lib/memcpy.S +++ b/arch/mips/lib/memcpy.S @@ -31,6 +31,7 @@ #include #include +#include #include #define dst a0 @@ -622,6 +623,7 @@ SEXC(1) .align 5 LEAF(memmove) +EXPORT_SYMBOL(memmove) ADD t0, a0, a2 ADD t1, a1, a2 sltu t0, a1, t0 # dst + len <= src -> memcpy @@ -674,6 +676,7 @@ LEAF(__rmemcpy) /* a0=dst a1=src a2=len */ * t6 is used as a flag to note inatomic mode. */ LEAF(__copy_user_inatomic) +EXPORT_SYMBOL(__copy_user_inatomic) b __copy_user_common li t6, 1 END(__copy_user_inatomic) @@ -686,9 +689,11 @@ LEAF(__copy_user_inatomic) */ .align 5 LEAF(memcpy) /* a0=dst a1=src a2=len */ +EXPORT_SYMBOL(memcpy) move v0, dst /* return value */ .L__memcpy: FEXPORT(__copy_user) +EXPORT_SYMBOL(__copy_user) li t6, 0 /* not inatomic */ __copy_user_common: /* Legacy Mode, user <-> user */ @@ -704,6 +709,7 @@ __copy_user_common: */ LEAF(__copy_user_inatomic_eva) +EXPORT_SYMBOL(__copy_user_inatomic_eva) b __copy_from_user_common li t6, 1 END(__copy_user_inatomic_eva) @@ -713,6 +719,7 @@ LEAF(__copy_user_inatomic_eva) */ LEAF(__copy_from_user_eva) +EXPORT_SYMBOL(__copy_from_user_eva) li t6, 0 /* not inatomic */ __copy_from_user_common: __BUILD_COPY_USER EVA_MODE USEROP KERNELOP @@ -725,6 +732,7 @@ END(__copy_from_user_eva) */ LEAF(__copy_to_user_eva) +EXPORT_SYMBOL(__copy_to_user_eva) __BUILD_COPY_USER EVA_MODE KERNELOP USEROP END(__copy_to_user_eva) @@ -733,6 +741,7 @@ END(__copy_to_user_eva) */ LEAF(__copy_in_user_eva) +EXPORT_SYMBOL(__copy_in_user_eva) __BUILD_COPY_USER EVA_MODE USEROP USEROP END(__copy_in_user_eva) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 18a1ccd4d134..a1456664d6c2 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -10,6 +10,7 @@ */ #include #include +#include #include #if LONGSIZE == 4 @@ -270,6 +271,7 @@ */ LEAF(memset) +EXPORT_SYMBOL(memset) beqz a1, 1f move v0, a0 /* result */ @@ -285,13 +287,16 @@ LEAF(memset) 1: #ifndef CONFIG_EVA FEXPORT(__bzero) +EXPORT_SYMBOL(__bzero) #else FEXPORT(__bzero_kernel) +EXPORT_SYMBOL(__bzero_kernel) #endif __BUILD_BZERO LEGACY_MODE #ifdef CONFIG_EVA LEAF(__bzero) +EXPORT_SYMBOL(__bzero) __BUILD_BZERO EVA_MODE END(__bzero) #endif From f44374f14c388d1170404d2206d4ff760d018212 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Nov 2016 11:14:16 +0000 Subject: [PATCH 0177/1587] MIPS: Export {copy, clear}_page functions alongside their definitions Now that EXPORT_SYMBOL can be used from assembly source, move the EXPORT_SYMBOL invocations for the copy_page & clear_page functions to be alongside their definitions. With this change there are no longer any symbols exported from mips_ksyms.c so remove the file. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14515/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 2 +- arch/mips/kernel/mips_ksyms.c | 24 ------------------------ arch/mips/mm/page-funcs.S | 3 +++ arch/mips/mm/page.c | 2 ++ 4 files changed, 6 insertions(+), 25 deletions(-) delete mode 100644 arch/mips/kernel/mips_ksyms.c diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 904a9c48553a..9a0e37b92ce0 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_SYNC_R4K) += sync-r4k.o obj-$(CONFIG_DEBUG_FS) += segment.o obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-$(CONFIG_MODULES) += mips_ksyms.o module.o +obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c deleted file mode 100644 index f01838faae2b..000000000000 --- a/arch/mips/kernel/mips_ksyms.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Export MIPS-specific functions needed for loadable modules. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05, 12 by Ralf Baechle - * Copyright (C) 1999, 2000, 01 Silicon Graphics, Inc. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Functions that operate on entire pages. Mostly used by memory management. - */ -EXPORT_SYMBOL(clear_page); -EXPORT_SYMBOL(copy_page); diff --git a/arch/mips/mm/page-funcs.S b/arch/mips/mm/page-funcs.S index 48a6b38ff13e..43181ac0a1af 100644 --- a/arch/mips/mm/page-funcs.S +++ b/arch/mips/mm/page-funcs.S @@ -9,6 +9,7 @@ * Copyright (C) 2012 Ralf Baechle */ #include +#include #include #ifdef CONFIG_SIBYTE_DMA_PAGEOPS @@ -29,6 +30,7 @@ */ EXPORT(__clear_page_start) LEAF(cpu_clear_page_function_name) +EXPORT_SYMBOL(cpu_clear_page_function_name) 1: j 1b /* Dummy, will be replaced. */ .space 288 END(cpu_clear_page_function_name) @@ -44,6 +46,7 @@ EXPORT(__clear_page_end) */ EXPORT(__copy_page_start) LEAF(cpu_copy_page_function_name) +EXPORT_SYMBOL(cpu_copy_page_function_name) 1: j 1b /* Dummy, will be replaced. */ .space 1344 END(cpu_copy_page_function_name) diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index 6f804f5960ab..d5d02993aa21 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -661,6 +661,7 @@ void clear_page(void *page) ; __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); } +EXPORT_SYMBOL(clear_page); void copy_page(void *to, void *from) { @@ -687,5 +688,6 @@ void copy_page(void *to, void *from) ; __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); } +EXPORT_SYMBOL(copy_page); #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */ From a8b3b0c94ac282628f0668d1366239a3fa72dc9d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Sep 2016 15:18:21 +0100 Subject: [PATCH 0178/1587] MIPS: Netlogic: Fix assembler warning from smpboot.S The netlogic platform can be built for either MIPS32 or MIPS64, and when built for MIPS32 (as by nlm_xlr_defconfig) the use of the dla pseudo-instruction leads to warnings such as the following from recent versions of the GNU assembler: arch/mips/netlogic/common/smpboot.S: Assembler messages: arch/mips/netlogic/common/smpboot.S:62: Warning: dla used to load 32-bit register; recommend using la instead arch/mips/netlogic/common/smpboot.S:63: Warning: dla used to load 32-bit register; recommend using la instead Avoid these warnings by using the PTR_LA macro to make use of the appropriate la or dla pseudo-instruction for the build. Signed-off-by: Paul Burton Fixes: 66d29985fab8 ("MIPS: Netlogic: Merge some of XLR/XLP wakup code") Cc: James Hogan Cc: Jayachandran C Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14185/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/common/smpboot.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index f0cc4c9de2bb..509c1a7e7c05 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -59,8 +59,8 @@ NESTED(xlp_boot_core0_siblings, PT_SIZE, sp) sync /* find the location to which nlm_boot_siblings was relocated */ li t0, CKSEG1ADDR(RESET_VEC_PHYS) - dla t1, nlm_reset_entry - dla t2, nlm_boot_siblings + PTR_LA t1, nlm_reset_entry + PTR_LA t2, nlm_boot_siblings dsubu t2, t1 daddu t2, t0 /* call it */ From 5d0a99d6afd80d375fcfea26467eb5b219b9f9d4 Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Fri, 12 Aug 2016 18:56:03 +0800 Subject: [PATCH 0179/1587] MIPS: Loongson1B: Change the OSC clock name This patch changes the OSC clock name to "osc_clk" as expected by all clock users. Signed-off-by: Kelvin Cheung Cc: linux-mips@linux-mips.org Cc: linux-clk@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13903/ Signed-off-by: Ralf Baechle --- arch/mips/loongson32/common/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index a3dabe940b03..100f23dfa438 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -69,7 +69,7 @@ void __init ls1x_serial_set_uartclk(struct platform_device *pdev) /* CPUFreq */ static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = { .clk_name = "cpu_clk", - .osc_clk_name = "osc_33m_clk", + .osc_clk_name = "osc_clk", .max_freq = 266 * 1000, .min_freq = 33 * 1000, }; From 819da1ead13621edd4f05df730651cf5b623de7e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 19 Aug 2016 18:13:34 +0100 Subject: [PATCH 0180/1587] MIPS: c-r4k: Treat I6400 dcache as though physically indexed The L1 data cache in I6400 CPUs is indexed by physical address bits if an entry for the address is present in the DTLB early enough in the pipelined execution of a memory access instruction. If an entry is not present then it's indexed by virtual address bits, but hardware will check in a later pipeline stage when a DTLB entry has been created whether the virtual address bits used match the physical address bits, and if not will transparently restart the memory access instruction. This means that although it isn't always physically indexed, it appears so to software & we can treat the I6400 L1 data cache as being physically indexed in order to avoid considering aliasing. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14016/ Signed-off-by: Ralf Baechle --- arch/mips/mm/c-r4k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 88cfaf81c958..86f21391eb09 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1452,6 +1452,7 @@ static void probe_pcache(void) switch (current_cpu_type()) { case CPU_20KC: case CPU_25KF: + case CPU_I6400: case CPU_SB1: case CPU_SB1A: case CPU_XLR: @@ -1478,7 +1479,6 @@ static void probe_pcache(void) case CPU_PROAPTIV: case CPU_M5150: case CPU_QEMU_GENERIC: - case CPU_I6400: case CPU_P6600: case CPU_M6250: if (!(read_c0_config7() & MIPS_CONF7_IAR) && From d66f99bc46925831236cf2335fcc6087d34e2195 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 19 Aug 2016 18:13:35 +0100 Subject: [PATCH 0181/1587] MIPS: c-r4k: Treat physically indexed dcaches as not aliasing Physically indexed caches cannot suffer from virtual aliasing, so clear the MIPS_CACHE_ALIASES bit in order to ensure we don't do extra work avoiding aliasing that cannot happen. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14017/ Signed-off-by: Ralf Baechle --- arch/mips/mm/c-r4k.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 86f21391eb09..e7f798d55fbc 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1497,6 +1497,10 @@ static void probe_pcache(void) c->dcache.flags |= MIPS_CACHE_ALIASES; } + /* Physically indexed caches don't suffer from virtual aliasing */ + if (c->dcache.flags & MIPS_CACHE_PINDEX) + c->dcache.flags &= ~MIPS_CACHE_ALIASES; + switch (current_cpu_type()) { case CPU_20KC: /* From 48ed33c1b3737eb1324c1ae023a8eeccad60cef9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 19 Aug 2016 18:13:36 +0100 Subject: [PATCH 0182/1587] MIPS: sc-mips: L2 cache is inclusive of L1 dcache for CM3 In systems with CM3 & higher, the L2 cache is inclusive of the L1 dcache. Indicate this such that cpu_has_inclusive_pcaches evaluates true and we avoid some unnecessary cache ops during DMA cache maintenance. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14018/ Signed-off-by: Ralf Baechle --- arch/mips/mm/sc-mips.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 286a4d5a1884..c909c3342729 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -181,6 +181,7 @@ static int __init mips_sc_probe_cm3(void) if (c->scache.linesz) { c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + c->options |= MIPS_CPU_INCLUSIVE_CACHES; return 1; } From 08d90c81b714482dceb5323d14f6617bcf55ee61 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Dec 2016 23:52:58 +0000 Subject: [PATCH 0183/1587] MIPS: ralink: Fix incorrect assignment on ralink_soc ralink_soc sould be assigned to RT3883_SOC, replace incorrect comparision with assignment. Signed-off-by: Colin Ian King Fixes: 418d29c87061 ("MIPS: ralink: Unify SoC id handling") Cc: John Crispin Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14903/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/rt3883.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index 141c597ec324..f869052e4a0d 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -157,5 +157,5 @@ void prom_soc_init(struct ralink_soc_info *soc_info) rt2880_pinmux_data = rt3883_pinmux_data; - ralink_soc == RT3883_SOC; + ralink_soc = RT3883_SOC; } From 209ec69ab3cd81f1577c5af39f7b07a168cd28bc Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 26 Dec 2016 19:57:52 +0100 Subject: [PATCH 0184/1587] MIPS: zboot: Consolidate compiler flag filtering. Al Viro noticed that we were using two different methods to filter out flags from KBUILD_CFLAGS. Signed-off-by: Ralf Baechle Reported-by: Al Viro --- arch/mips/boot/compressed/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 41564a4db6f7..c675eece389a 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -18,7 +18,7 @@ include $(srctree)/arch/mips/Kbuild.platforms BOOT_HEAP_SIZE := 0x400000 # Disable Function Tracer -KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//") +KBUILD_CFLAGS := $(filter-out -pg, $(KBUILD_CFLAGS)) KBUILD_CFLAGS := $(filter-out -fstack-protector, $(KBUILD_CFLAGS)) From ffcfae3823751c72b615b57f700e563667002d09 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 4 Jan 2017 11:15:07 +0100 Subject: [PATCH 0185/1587] spi: rspi: Remove useless memory allocation failure message Printing an error on memory allocation failure is unnecessary. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 9daf50031737..58b7e68013f3 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1227,10 +1227,8 @@ static int rspi_probe(struct platform_device *pdev) const struct spi_ops *ops; master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); - if (master == NULL) { - dev_err(&pdev->dev, "spi_alloc_master error.\n"); + if (master == NULL) return -ENOMEM; - } of_id = of_match_device(rspi_of_match, &pdev->dev); if (of_id) { From e7ad4a73364c21f40963a35631b285b60fa3198c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 4 Jan 2017 11:15:08 +0100 Subject: [PATCH 0186/1587] spi: sh-msiof: Remove useless memory allocation failure message Printing an error on memory allocation failure is unnecessary. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 1f00eeb0b5a3..2ce15ca97782 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1164,10 +1164,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) int ret; master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv)); - if (master == NULL) { - dev_err(&pdev->dev, "failed to allocate spi master\n"); + if (master == NULL) return -ENOMEM; - } p = spi_master_get_devdata(master); From 63971c5682bf89e15083733dcd7b4610e789e843 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jan 2017 13:44:29 +0200 Subject: [PATCH 0187/1587] spi: pxa2xx: fix indentation of the comments in header Just for sake of readability fix the indentation of the comments in pxa2xx_ssp.h header file. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- include/linux/pxa2xx_ssp.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index 2d6f0c39ed68..a0522328d7aa 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -90,9 +90,9 @@ #define SSSR_RFL_MASK (0xf << 12) /* Receive FIFO Level mask */ #define SSCR1_TFT (0x000003c0) /* Transmit FIFO Threshold (mask) */ -#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */ +#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */ #define SSCR1_RFT (0x00003c00) /* Receive FIFO Threshold (mask) */ -#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */ +#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */ #define RX_THRESH_CE4100_DFLT 2 #define TX_THRESH_CE4100_DFLT 2 @@ -106,9 +106,9 @@ #define CE4100_SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */ /* QUARK_X1000 SSCR0 bit definition */ -#define QUARK_X1000_SSCR0_DSS (0x1F) /* Data Size Select (mask) */ -#define QUARK_X1000_SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..32] */ -#define QUARK_X1000_SSCR0_FRF (0x3 << 5) /* FRame Format (mask) */ +#define QUARK_X1000_SSCR0_DSS (0x1F << 0) /* Data Size Select (mask) */ +#define QUARK_X1000_SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..32] */ +#define QUARK_X1000_SSCR0_FRF (0x3 << 5) /* FRame Format (mask) */ #define QUARK_X1000_SSCR0_Motorola (0x0 << 5) /* Motorola's Serial Peripheral Interface (SPI) */ #define RX_THRESH_QUARK_X1000_DFLT 1 @@ -121,8 +121,8 @@ #define QUARK_X1000_SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..32] */ #define QUARK_X1000_SSCR1_RFT (0x1F << 11) /* Receive FIFO Threshold (mask) */ #define QUARK_X1000_SSCR1_RxTresh(x) (((x) - 1) << 11) /* level [1..32] */ -#define QUARK_X1000_SSCR1_STRF (1 << 17) /* Select FIFO or EFWR */ -#define QUARK_X1000_SSCR1_EFWR (1 << 16) /* Enable FIFO Write/Read */ +#define QUARK_X1000_SSCR1_STRF (1 << 17) /* Select FIFO or EFWR */ +#define QUARK_X1000_SSCR1_EFWR (1 << 16) /* Enable FIFO Write/Read */ /* extra bits in PXA255, PXA26x and PXA27x SSP ports */ #define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */ From 25014521603f70225c1e6fa232839614f7b4f692 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jan 2017 13:47:31 +0200 Subject: [PATCH 0188/1587] spi: pxa2xx-pci: Enable DMA for Intel Merrifield SPI controller on Intel Merrifield is backed by DMA engine. Add necessary bits to support it. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 58d2d48e16a5..868452d8e3e1 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -41,6 +41,13 @@ struct pxa_spi_info { static struct dw_dma_slave byt_tx_param = { .dst_id = 0 }; static struct dw_dma_slave byt_rx_param = { .src_id = 1 }; +static struct dw_dma_slave mrfld3_tx_param = { .dst_id = 15 }; +static struct dw_dma_slave mrfld3_rx_param = { .src_id = 14 }; +static struct dw_dma_slave mrfld5_tx_param = { .dst_id = 13 }; +static struct dw_dma_slave mrfld5_rx_param = { .src_id = 12 }; +static struct dw_dma_slave mrfld6_tx_param = { .dst_id = 11 }; +static struct dw_dma_slave mrfld6_rx_param = { .src_id = 10 }; + static struct dw_dma_slave bsw0_tx_param = { .dst_id = 0 }; static struct dw_dma_slave bsw0_rx_param = { .src_id = 1 }; static struct dw_dma_slave bsw1_tx_param = { .dst_id = 6 }; @@ -93,22 +100,39 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + struct pci_dev *dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); + struct dw_dma_slave *tx, *rx; + switch (PCI_FUNC(dev->devfn)) { case 0: c->port_id = 3; c->num_chipselect = 1; + c->tx_param = &mrfld3_tx_param; + c->rx_param = &mrfld3_rx_param; break; case 1: c->port_id = 5; c->num_chipselect = 4; + c->tx_param = &mrfld5_tx_param; + c->rx_param = &mrfld5_rx_param; break; case 2: c->port_id = 6; c->num_chipselect = 1; + c->tx_param = &mrfld6_tx_param; + c->rx_param = &mrfld6_rx_param; break; default: return -ENODEV; } + + tx = c->tx_param; + tx->dma_dev = &dma_dev->dev; + + rx = c->rx_param; + rx->dma_dev = &dma_dev->dev; + + c->dma_filter = lpss_dma_filter; return 0; } From 74e30f96ad21a338f9492325bc73c452049c2548 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 3 Jan 2017 13:30:41 +0800 Subject: [PATCH 0189/1587] ACPICA: Fix for implicit result conversion for the ToXXX functions ACPICA commit e1342c9f2dde37a67e916099658b65984ef8a434 Implicit result conversion was incorrectly disabled for the following functions: FromBCD ToBCD ToDecimalString ToHexString ToInteger ToBuffer Link: https://github.com/acpica/acpica/commit/e1342c9f Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acopcode.h | 14 +++++++------- drivers/acpi/acpica/amlcode.h | 20 +++++++++++++++++--- drivers/acpi/acpica/exconvrt.c | 1 - drivers/acpi/acpica/exresop.c | 1 - 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index ca4bda1a60be..84d611b5231f 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -249,7 +249,7 @@ #define ARGI_FIELD_OP ARGI_INVALID_OPCODE #define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_IF_OP ARGI_INVALID_OPCODE #define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) #define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE @@ -313,12 +313,12 @@ #define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE #define ARGI_TIMER_OP ARG_NONE -#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) -#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF) +#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF) +#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF) +#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF) +#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) #define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 6bd8d4bcff65..8a0f95931812 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -277,9 +277,23 @@ #define ARGI_DEVICE_REF 0x0D #define ARGI_REFERENCE 0x0E #define ARGI_TARGETREF 0x0F /* Target, subject to implicit conversion */ -#define ARGI_FIXED_TARGET 0x10 /* Target, no implicit conversion */ -#define ARGI_SIMPLE_TARGET 0x11 /* Name, Local, Arg -- no implicit conversion */ -#define ARGI_STORE_TARGET 0x12 /* Target for store is TARGETREF + package objects */ +#define ARGI_SIMPLE_TARGET 0x10 /* Name, Local, Arg -- no implicit conversion */ +#define ARGI_STORE_TARGET 0x11 /* Target for store is TARGETREF + package objects */ +/* + * #define ARGI_FIXED_TARGET 0x10 Target, no implicit conversion + * + * Removed 10/2016. ARGI_FIXED_TARGET was used for these operators: + * from_BCD + * to_BCD + * to_decimal_string + * to_hex_string + * to_integer + * to_buffer + * The purpose of this type was to disable "implicit result conversion", + * but this was incorrect per the ACPI spec and other ACPI implementations. + * These operators now have the target operand defined as a normal + * ARGI_TARGETREF. + */ /* Multiple/complex types */ diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 588ad1409dbe..83202dbe88b9 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -592,7 +592,6 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type, */ switch (GET_CURRENT_ARG_TYPE(walk_state->op_info->runtime_args)) { case ARGI_SIMPLE_TARGET: - case ARGI_FIXED_TARGET: case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ switch (destination_type) { diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index f29eba1dc5e9..d4c386d16b44 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -305,7 +305,6 @@ acpi_ex_resolve_operands(u16 opcode, case ARGI_OBJECT_REF: case ARGI_DEVICE_REF: case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ - case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ case ARGI_SIMPLE_TARGET: /* Name, Local, or arg - no implicit conversion */ case ARGI_STORE_TARGET: From ce87e09dd88c61f9088768a7708828423549725c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 28 Dec 2016 15:29:43 +0800 Subject: [PATCH 0190/1587] ACPICA: Parser: Allow method invocations as target operands ACPICA commit a6cca7a4786cdbfd29cea67e84b5b01a8ae6ff1c Method invocations as target operands are allowed as target operands in the ASL grammar. This change implements support for this. Method must return a reference for this to work properly at runtime, however. Link: https://github.com/acpica/acpica/commit/a6cca7a4 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psargs.c | 82 ++++++++++++++++++++-------------- drivers/acpi/acpica/psloop.c | 4 ++ drivers/acpi/acpica/psobject.c | 10 ++++- drivers/acpi/acpica/pstree.c | 10 +++-- 4 files changed, 67 insertions(+), 39 deletions(-) diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index c29c930ffa08..4e1065e84da8 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -269,23 +269,13 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, */ if (ACPI_SUCCESS(status) && possible_method_call && (node->type == ACPI_TYPE_METHOD)) { - if (walk_state->opcode == AML_UNLOAD_OP) { - /* - * acpi_ps_get_next_namestring has increased the AML pointer, - * so we need to restore the saved AML pointer for method call. - */ - walk_state->parser_state.aml = start; - walk_state->arg_count = 1; - acpi_ps_init_op(arg, AML_INT_METHODCALL_OP); - return_ACPI_STATUS(AE_OK); - } /* This name is actually a control method invocation */ method_desc = acpi_ns_get_attached_object(node); ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Control Method - %p Desc %p Path=%p\n", node, - method_desc, path)); + "Control Method invocation %4.4s - %p Desc %p Path=%p\n", + node->name.ascii, node, method_desc, path)); name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, start); if (!name_op) { @@ -719,6 +709,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE_PTR(ps_get_next_arg, parser_state); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Expected argument type ARGP: %s (%2.2X)\n", + acpi_ut_get_argument_type_name(arg_type), arg_type)); + switch (arg_type) { case ARGP_BYTEDATA: case ARGP_WORDDATA: @@ -796,11 +790,14 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, } break; - case ARGP_TARGET: - case ARGP_SUPERNAME: case ARGP_SIMPLENAME: case ARGP_NAME_OR_REF: + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "**** SimpleName/NameOrRef: %s (%2.2X)\n", + acpi_ut_get_argument_type_name(arg_type), + arg_type)); + subop = acpi_ps_peek_opcode(parser_state); if (subop == 0 || acpi_ps_is_leading_char(subop) || @@ -816,29 +813,41 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NO_MEMORY); } - /* To support super_name arg of Unload */ + status = + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_NOT_METHOD_CALL); + } else { + /* Single complex argument, nothing returned */ - if (walk_state->opcode == AML_UNLOAD_OP) { - status = - acpi_ps_get_next_namepath(walk_state, - parser_state, arg, - ACPI_POSSIBLE_METHOD_CALL); + walk_state->arg_count = 1; + } + break; - /* - * If the super_name argument is a method call, we have - * already restored the AML pointer, just free this Arg - */ - if (arg->common.aml_opcode == - AML_INT_METHODCALL_OP) { - acpi_ps_free_op(arg); - arg = NULL; - } - } else { - status = - acpi_ps_get_next_namepath(walk_state, - parser_state, arg, - ACPI_NOT_METHOD_CALL); + case ARGP_TARGET: + case ARGP_SUPERNAME: + + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "**** Target/Supername: %s (%2.2X)\n", + acpi_ut_get_argument_type_name(arg_type), + arg_type)); + + subop = acpi_ps_peek_opcode(parser_state); + if (subop == 0) { + + /* NULL target (zero). Convert to a NULL namepath */ + + arg = + acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, + parser_state->aml); + if (!arg) { + return_ACPI_STATUS(AE_NO_MEMORY); } + + status = + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_POSSIBLE_METHOD_CALL); } else { /* Single complex argument, nothing returned */ @@ -849,6 +858,11 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, case ARGP_DATAOBJ: case ARGP_TERMARG: + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "**** TermArg/DataObj: %s (%2.2X)\n", + acpi_ut_get_argument_type_name(arg_type), + arg_type)); + /* Single complex argument, nothing returned */ walk_state->arg_count = 1; diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 6a9f5059f682..ac022b556cd9 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -92,6 +92,10 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Get arguments for opcode [%s]\n", + op->common.aml_op_name)); + switch (op->common.aml_opcode) { case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ case AML_WORD_OP: /* AML_WORDDATA_ARG */ diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index db0e90342e82..4abf007f86c3 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -348,7 +348,15 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, argument_count) { op->common.flags |= ACPI_PARSEOP_TARGET; } - } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) { + } + + /* + * Special case for both Increment() and Decrement(), where + * the lone argument is both a source and a target. + */ + else if ((parent_scope->common.aml_opcode == AML_INCREMENT_OP) + || (parent_scope->common.aml_opcode == + AML_DECREMENT_OP)) { op->common.flags |= ACPI_PARSEOP_TARGET; } } diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index 0288cdbda88e..4266e5e445ed 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -129,10 +129,10 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) union acpi_parse_object *prev_arg; const struct acpi_opcode_info *op_info; - ACPI_FUNCTION_ENTRY(); + ACPI_FUNCTION_TRACE(ps_append_arg); if (!op) { - return; + return_VOID; } /* Get the info structure for this opcode */ @@ -144,7 +144,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X", op->common.aml_opcode)); - return; + return_VOID; } /* Check if this opcode requires argument sub-objects */ @@ -153,7 +153,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) /* Has no linked argument objects */ - return; + return_VOID; } /* Append the argument to the linked argument list */ @@ -181,6 +181,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) op->common.arg_list_length++; } + + return_VOID; } /******************************************************************************* From 9a947291374dbf377c4110f2387f3386d88cf5b0 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 28 Dec 2016 15:29:49 +0800 Subject: [PATCH 0191/1587] ACPICA: Fix a problem with recent extra support for control method invocations ACPICA commit b7dae343fbb8c392999a66f5e08be5744a5d07e2 This change fixes a problem with the recent support that enables control method invocations as Target operands to many ASL operators. Eliminates errors similar to: Needed type [Reference], found [Processor] Link: https://github.com/acpica/acpica/commit/b7dae343 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psargs.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 4e1065e84da8..b0e55a7d4bdf 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -269,6 +269,20 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, */ if (ACPI_SUCCESS(status) && possible_method_call && (node->type == ACPI_TYPE_METHOD)) { + if ((GET_CURRENT_ARG_TYPE(walk_state->arg_types) == + ARGP_SUPERNAME) + || (GET_CURRENT_ARG_TYPE(walk_state->arg_types) == + ARGP_TARGET)) { + /* + * acpi_ps_get_next_namestring has increased the AML pointer past + * the method invocation namestring, so we need to restore the + * saved AML pointer back to the original method invocation + * namestring. + */ + walk_state->parser_state.aml = start; + walk_state->arg_count = 1; + acpi_ps_init_op(arg, AML_INT_METHODCALL_OP); + } /* This name is actually a control method invocation */ @@ -833,7 +847,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, arg_type)); subop = acpi_ps_peek_opcode(parser_state); - if (subop == 0) { + if (subop == 0 || + acpi_ps_is_leading_char(subop) || + ACPI_IS_ROOT_PREFIX(subop) || + ACPI_IS_PARENT_PREFIX(subop)) { /* NULL target (zero). Convert to a NULL namepath */ @@ -848,6 +865,12 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, acpi_ps_get_next_namepath(walk_state, parser_state, arg, ACPI_POSSIBLE_METHOD_CALL); + + if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) { + acpi_ps_free_op(arg); + arg = NULL; + walk_state->arg_count = 1; + } } else { /* Single complex argument, nothing returned */ From 6b506235770fdb9796dd7bc806e5303bcac3b3fd Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 28 Dec 2016 15:29:56 +0800 Subject: [PATCH 0192/1587] ACPICA: Parser: Update parse info table for some operators ACPICA commit b90e39948954ff400cff1a3f8effddb67f15460b Operand for deref_of should not have been a term_arg, should be super_name. Rename NAME_OR_REF to SIMPLENAME. Link: https://github.com/acpica/acpica/commit/b90e3994 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acopcode.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index 84d611b5231f..245c1da191c4 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -92,7 +92,7 @@ #define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_NAME_OR_REF,ARGP_TARGET) +#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SIMPLENAME, ARGP_TARGET) #define ARGP_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_CONTINUE_OP ARG_NONE #define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) @@ -105,7 +105,7 @@ #define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) #define ARGP_DEBUG_OP ARG_NONE #define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) #define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET) #define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) @@ -152,14 +152,14 @@ #define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_NOOP_OP ARG_NONE #define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) -#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_NAME_OR_REF) +#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_SIMPLENAME) #define ARGP_ONE_OP ARG_NONE #define ARGP_ONES_OP ARG_NONE #define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) #define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) #define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) #define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) -#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_NAME_OR_REF) +#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SIMPLENAME) #define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) #define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) From e9ca038a94f5a41c0689c5f441fd9c5a567e6f39 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 28 Dec 2016 15:30:02 +0800 Subject: [PATCH 0193/1587] ACPICA: Update version to 20161222 ACPICA commit 0d5a056877c2e37e0bfce8d262cec339dc8d55fd ACPICA commit 5bea13a9e1eb2a0da99600d181afbc5fa075a9eb Version 20161222 Link: https://github.com/acpica/acpica/commit/0d5a0568 Link: https://github.com/acpica/acpica/commit/5bea13a9 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index f5e10dd8e86b..12f426661032 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20160930 +#define ACPI_CA_VERSION 0x20161222 #include #include From f64dad2628bdf62eac7ac145a6e31430376b65e4 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 14 Dec 2016 18:45:58 -0800 Subject: [PATCH 0194/1587] scsi: storvsc: Enable tracking of queue depth Enable tracking of queue depth. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 05526b71541b..ccb2101c6385 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1550,6 +1550,7 @@ static struct scsi_host_template scsi_driver = { /* Make sure we dont get a sg segment crosses a page boundary */ .dma_boundary = PAGE_SIZE-1, .no_write_same = 1, + .track_queue_depth = 1, }; enum { From 977965283526dd2e887331365da19b05c909a966 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 14 Dec 2016 18:45:59 -0800 Subject: [PATCH 0195/1587] scsi: storvsc: Remove the restriction on max segment size Remove the artificially imposed restriction on max segment size. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index ccb2101c6385..3b1c2f6528b4 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1267,8 +1267,6 @@ static int storvsc_do_io(struct hv_device *device, static int storvsc_device_configure(struct scsi_device *sdevice) { - blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); - blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY); blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ)); From d86adf482b843b3a58a9ec3b7c1ccdbf7c705db1 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 14 Dec 2016 18:46:00 -0800 Subject: [PATCH 0196/1587] scsi: storvsc: Enable multi-queue support Enable multi-q support. We will allocate the outgoing channel using the following policy: 1. We will make every effort to pick a channel that is in the same NUMA node that is initiating the I/O 2. The mapping between the guest CPU and the outgoing channel is persistent. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 113 ++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 3b1c2f6528b4..63f6b1ad57c5 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -458,6 +458,15 @@ struct storvsc_device { * Max I/O, the device can support. */ u32 max_transfer_bytes; + /* + * Number of sub-channels we will open. + */ + u16 num_sc; + struct vmbus_channel **stor_chns; + /* + * Mask of CPUs bound to subchannels. + */ + struct cpumask alloced_cpus; /* Used for vsc/vsp channel reset process */ struct storvsc_cmd_request init_request; struct storvsc_cmd_request reset_request; @@ -635,6 +644,11 @@ static void handle_sc_creation(struct vmbus_channel *new_sc) (void *)&props, sizeof(struct vmstorage_channel_properties), storvsc_on_channel_callback, new_sc); + + if (new_sc->state == CHANNEL_OPENED_STATE) { + stor_device->stor_chns[new_sc->target_cpu] = new_sc; + cpumask_set_cpu(new_sc->target_cpu, &stor_device->alloced_cpus); + } } static void handle_multichannel_storage(struct hv_device *device, int max_chns) @@ -651,6 +665,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns) if (!stor_device) return; + stor_device->num_sc = num_sc; request = &stor_device->init_request; vstor_packet = &request->vstor_packet; @@ -838,6 +853,25 @@ static int storvsc_channel_init(struct hv_device *device, bool is_fc) * support multi-channel. */ max_chns = vstor_packet->storage_channel_properties.max_channel_cnt; + + /* + * Allocate state to manage the sub-channels. + * We allocate an array based on the numbers of possible CPUs + * (Hyper-V does not support cpu online/offline). + * This Array will be sparseley populated with unique + * channels - primary + sub-channels. + * We will however populate all the slots to evenly distribute + * the load. + */ + stor_device->stor_chns = kzalloc(sizeof(void *) * num_possible_cpus(), + GFP_KERNEL); + if (stor_device->stor_chns == NULL) + return -ENOMEM; + + stor_device->stor_chns[device->channel->target_cpu] = device->channel; + cpumask_set_cpu(device->channel->target_cpu, + &stor_device->alloced_cpus); + if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN8) { if (vstor_packet->storage_channel_properties.flags & STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL) @@ -1198,17 +1232,64 @@ static int storvsc_dev_remove(struct hv_device *device) /* Close the channel */ vmbus_close(device->channel); + kfree(stor_device->stor_chns); kfree(stor_device); return 0; } +static struct vmbus_channel *get_og_chn(struct storvsc_device *stor_device, + u16 q_num) +{ + u16 slot = 0; + u16 hash_qnum; + struct cpumask alloced_mask; + int num_channels, tgt_cpu; + + if (stor_device->num_sc == 0) + return stor_device->device->channel; + + /* + * Our channel array is sparsley populated and we + * initiated I/O on a processor/hw-q that does not + * currently have a designated channel. Fix this. + * The strategy is simple: + * I. Ensure NUMA locality + * II. Distribute evenly (best effort) + * III. Mapping is persistent. + */ + + cpumask_and(&alloced_mask, &stor_device->alloced_cpus, + cpumask_of_node(cpu_to_node(q_num))); + + num_channels = cpumask_weight(&alloced_mask); + if (num_channels == 0) + return stor_device->device->channel; + + hash_qnum = q_num; + while (hash_qnum >= num_channels) + hash_qnum -= num_channels; + + for_each_cpu(tgt_cpu, &alloced_mask) { + if (slot == hash_qnum) + break; + slot++; + } + + stor_device->stor_chns[q_num] = stor_device->stor_chns[tgt_cpu]; + + return stor_device->stor_chns[q_num]; +} + + static int storvsc_do_io(struct hv_device *device, - struct storvsc_cmd_request *request) + struct storvsc_cmd_request *request, u16 q_num) { struct storvsc_device *stor_device; struct vstor_packet *vstor_packet; struct vmbus_channel *outgoing_channel; int ret = 0; + struct cpumask alloced_mask; + int tgt_cpu; vstor_packet = &request->vstor_packet; stor_device = get_out_stor_device(device); @@ -1222,7 +1303,26 @@ static int storvsc_do_io(struct hv_device *device, * Select an an appropriate channel to send the request out. */ - outgoing_channel = vmbus_get_outgoing_channel(device->channel); + if (stor_device->stor_chns[q_num] != NULL) { + outgoing_channel = stor_device->stor_chns[q_num]; + if (outgoing_channel->target_cpu == smp_processor_id()) { + /* + * Ideally, we want to pick a different channel if + * available on the same NUMA node. + */ + cpumask_and(&alloced_mask, &stor_device->alloced_cpus, + cpumask_of_node(cpu_to_node(q_num))); + for_each_cpu(tgt_cpu, &alloced_mask) { + if (tgt_cpu != outgoing_channel->target_cpu) { + outgoing_channel = + stor_device->stor_chns[tgt_cpu]; + break; + } + } + } + } else { + outgoing_channel = get_og_chn(stor_device, q_num); + } vstor_packet->flags |= REQUEST_COMPLETION_FLAG; @@ -1522,7 +1622,8 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) cmd_request->payload_sz = payload_sz; /* Invokes the vsc to start an IO */ - ret = storvsc_do_io(dev, cmd_request); + ret = storvsc_do_io(dev, cmd_request, get_cpu()); + put_cpu(); if (ret == -EAGAIN) { /* no more space */ @@ -1679,6 +1780,11 @@ static int storvsc_probe(struct hv_device *device, * from the host. */ host->sg_tablesize = (stor_device->max_transfer_bytes >> PAGE_SHIFT); + /* + * Set the number of HW queues we are supporting. + */ + if (stor_device->num_sc != 0) + host->nr_hw_queues = stor_device->num_sc + 1; /* Register the HBA and start the scsi bus scan */ ret = scsi_add_host(host, &device->device); @@ -1715,6 +1821,7 @@ err_out2: goto err_out0; err_out1: + kfree(stor_device->stor_chns); kfree(stor_device); err_out0: From 3cd6d3d9b1abab8dcdf0800224ce26daac24eea2 Mon Sep 17 00:00:00 2001 From: Long Li Date: Wed, 14 Dec 2016 18:46:01 -0800 Subject: [PATCH 0197/1587] scsi: storvsc: use tagged SRB requests if supported by the device Properly set SRB flags when hosting device supports tagged queuing. This patch improves the performance on Fiber Channel disks. Signed-off-by: Long Li Reviewed-by: K. Y. Srinivasan Signed-off-by: K. Y. Srinivasan Cc: Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 63f6b1ad57c5..320938720544 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -136,6 +136,8 @@ struct hv_fc_wwn_packet { #define SRB_FLAGS_PORT_DRIVER_RESERVED 0x0F000000 #define SRB_FLAGS_CLASS_DRIVER_RESERVED 0xF0000000 +#define SP_UNTAGGED ((unsigned char) ~0) +#define SRB_SIMPLE_TAG_REQUEST 0x20 /* * Platform neutral description of a scsi request - @@ -1549,6 +1551,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + if (scmnd->device->tagged_supported) { + vm_srb->win8_extension.srb_flags |= + (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE); + vm_srb->win8_extension.queue_tag = SP_UNTAGGED; + vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST; + } + /* Build the SRB */ switch (scmnd->sc_data_direction) { case DMA_TO_DEVICE: From bba5dc332ec2d3a685cb4dae668c793f6a3713a3 Mon Sep 17 00:00:00 2001 From: Long Li Date: Wed, 14 Dec 2016 18:46:02 -0800 Subject: [PATCH 0198/1587] scsi: storvsc: properly handle SRB_ERROR when sense message is present When sense message is present on error, we should pass along to the upper layer to decide how to deal with the error. This patch fixes connectivity issues with Fiber Channel devices. Signed-off-by: Long Li Reviewed-by: K. Y. Srinivasan Signed-off-by: K. Y. Srinivasan Cc: Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 320938720544..3c92dc2a25a0 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -924,6 +924,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, switch (SRB_STATUS(vm_srb->srb_status)) { case SRB_STATUS_ERROR: + /* + * Let upper layer deal with error when + * sense message is present. + */ + + if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) + break; /* * If there is an error; offline the device since all * error recovery strategies would have already been From 40630f462824ee24bc00d692865c86c3828094e0 Mon Sep 17 00:00:00 2001 From: Long Li Date: Wed, 14 Dec 2016 18:46:03 -0800 Subject: [PATCH 0199/1587] scsi: storvsc: properly set residual data length on errors On I/O errors, the Windows driver doesn't set data_transfer_length on error conditions other than SRB_STATUS_DATA_OVERRUN. In these cases we need to set data_transfer_length to 0, indicating there is no data transferred. On SRB_STATUS_DATA_OVERRUN, data_transfer_length is set by the Windows driver to the actual data transferred. Reported-by: Shiva Krishna Signed-off-by: Long Li Reviewed-by: K. Y. Srinivasan Signed-off-by: K. Y. Srinivasan Cc: Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 3c92dc2a25a0..888e16ec8554 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -377,6 +377,7 @@ enum storvsc_request_type { #define SRB_STATUS_SUCCESS 0x01 #define SRB_STATUS_ABORTED 0x02 #define SRB_STATUS_ERROR 0x04 +#define SRB_STATUS_DATA_OVERRUN 0x12 #define SRB_STATUS(status) \ (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) @@ -996,6 +997,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, struct scsi_cmnd *scmnd = cmd_request->cmd; struct scsi_sense_hdr sense_hdr; struct vmscsi_request *vm_srb; + u32 data_transfer_length; struct Scsi_Host *host; u32 payload_sz = cmd_request->payload_sz; void *payload = cmd_request->payload; @@ -1003,6 +1005,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, host = stor_dev->host; vm_srb = &cmd_request->vstor_packet.vm_srb; + data_transfer_length = vm_srb->data_transfer_length; scmnd->result = vm_srb->scsi_status; @@ -1016,13 +1019,20 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, &sense_hdr); } - if (vm_srb->srb_status != SRB_STATUS_SUCCESS) + if (vm_srb->srb_status != SRB_STATUS_SUCCESS) { storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc, sense_hdr.ascq); + /* + * The Windows driver set data_transfer_length on + * SRB_STATUS_DATA_OVERRUN. On other errors, this value + * is untouched. In these cases we set it to 0. + */ + if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN) + data_transfer_length = 0; + } scsi_set_resid(scmnd, - cmd_request->payload->range.len - - vm_srb->data_transfer_length); + cmd_request->payload->range.len - data_transfer_length); scmnd->scsi_done(scmnd); From e0165f20447c8ca1d367725ee94d8ec9f38ca275 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:20 -0800 Subject: [PATCH 0200/1587] scsi: lpfc: Clear the VendorVersion in the PLOGI/PLOGI ACC payload Clear the VendorVersion in the PLOGI/PLOGI ACC payload Vendor version info may have been set on fabric login. Before sending PLOGI payloads, ensure that it's cleared. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 6 ++++++ drivers/scsi/lpfc/lpfc_hw.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 236e4e51d161..27f0cbb9b278 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1999,6 +1999,9 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; + sp->cmn.valid_vendor_ver_level = 0; + memset(sp->vendorVersion, 0, sizeof(sp->vendorVersion)); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue PLOGI: did:x%x", did, 0, 0); @@ -3988,6 +3991,9 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, } else { memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); + + sp->cmn.valid_vendor_ver_level = 0; + memset(sp->vendorVersion, 0, sizeof(sp->vendorVersion)); } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 822654322e67..3b970d370600 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -360,6 +360,12 @@ struct csp { * Word 1 Bit 30 in PLOGI request is random offset */ #define virtual_fabric_support randomOffset /* Word 1, bit 30 */ +/* + * Word 1 Bit 29 in common service parameter is overloaded. + * Word 1 Bit 29 in FLOGI response is multiple NPort assignment + * Word 1 Bit 29 in FLOGI/PLOGI request is Valid Vendor Version Level + */ +#define valid_vendor_ver_level response_multiple_NPort /* Word 1, bit 29 */ #ifdef __BIG_ENDIAN_BITFIELD uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */ uint16_t randomOffset:1; /* FC Word 1, bit 30 */ From b2fd103b05feabbc86db726ae121da94639892d7 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:21 -0800 Subject: [PATCH 0201/1587] scsi: lpfc: Correct error in setting OS Driver Version with FW Correct error in setting OS Driver Version with FW. Prior length was too short. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4faa7672fc1d..f895cb9c89a3 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -6306,7 +6306,8 @@ lpfc_set_host_data(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) LPFC_SLI4_MBX_EMBED); mbox->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_OS_DRIVER_VERSION; - mbox->u.mqe.un.set_host_data.param_len = 8; + mbox->u.mqe.un.set_host_data.param_len = + LPFC_HOST_OS_DRIVER_VERSION_SIZE; snprintf(mbox->u.mqe.un.set_host_data.data, LPFC_HOST_OS_DRIVER_VERSION_SIZE, "Linux %s v"LPFC_DRIVER_VERSION, From 8c6a6f4076984ab15c33c2a52a10b681359f5a2a Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:22 -0800 Subject: [PATCH 0202/1587] scsi: lpfc: Deprecate lpfc_soft_wwn parameter Deprecate lpfc_soft_wwn parameter. No longer allow override of hw-assigned wwns Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 4 - drivers/scsi/lpfc/lpfc_attr.c | 216 ---------------------------------- drivers/scsi/lpfc/lpfc_init.c | 16 +-- 3 files changed, 3 insertions(+), 233 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8a20b4e86224..341b656e9d9d 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -729,8 +729,6 @@ struct lpfc_hba { uint32_t cfg_sg_seg_cnt; uint32_t cfg_prot_sg_seg_cnt; uint32_t cfg_sg_dma_buf_size; - uint64_t cfg_soft_wwnn; - uint64_t cfg_soft_wwpn; uint32_t cfg_hba_queue_depth; uint32_t cfg_enable_hba_reset; uint32_t cfg_enable_hba_heartbeat; @@ -835,8 +833,6 @@ struct lpfc_hba { #define VPD_PORT 0x8 /* valid vpd port data */ #define VPD_MASK 0xf /* mask for any vpd data */ - uint8_t soft_wwn_enable; - struct timer_list fcp_poll_timer; struct timer_list eratt_poll; uint32_t eratt_poll_interval; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c84775562c65..98c40a734a36 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1987,7 +1987,6 @@ static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show, NULL); -static char *lpfc_soft_wwn_key = "C99G71SL8032A"; #define WWN_SZ 8 /** * lpfc_wwn_set - Convert string to the 8 byte WWN value. @@ -2031,216 +2030,6 @@ lpfc_wwn_set(const char *buf, size_t cnt, char wwn[]) } return 0; } -/** - * lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing the string lpfc_soft_wwn_key. - * @count: must be size of lpfc_soft_wwn_key. - * - * Returns: - * -EINVAL if the buffer does not contain lpfc_soft_wwn_key - * length of buf indicates success - **/ -static ssize_t -lpfc_soft_wwn_enable_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - unsigned int cnt = count; - - /* - * We're doing a simple sanity check for soft_wwpn setting. - * We require that the user write a specific key to enable - * the soft_wwpn attribute to be settable. Once the attribute - * is written, the enable key resets. If further updates are - * desired, the key must be written again to re-enable the - * attribute. - * - * The "key" is not secret - it is a hardcoded string shown - * here. The intent is to protect against the random user or - * application that is just writing attributes. - */ - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if ((cnt != strlen(lpfc_soft_wwn_key)) || - (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0)) - return -EINVAL; - - phba->soft_wwn_enable = 1; - return count; -} -static DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL, - lpfc_soft_wwn_enable_store); - -/** - * lpfc_soft_wwpn_show - Return the cfg soft ww port name of the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the wwpn in hexadecimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "0x%llx\n", - (unsigned long long)phba->cfg_soft_wwpn); -} - -/** - * lpfc_soft_wwpn_store - Set the ww port name of the adapter - * @dev class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: contains the wwpn in hexadecimal. - * @count: number of wwpn bytes in buf - * - * Returns: - * -EACCES hba reset not enabled, adapter over temp - * -EINVAL soft wwn not enabled, count is invalid, invalid wwpn byte invalid - * -EIO error taking adapter offline or online - * value of count on success - **/ -static ssize_t -lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct completion online_compl; - int stat1 = 0, stat2 = 0; - unsigned int cnt = count; - u8 wwpn[WWN_SZ]; - int rc; - - if (!phba->cfg_enable_hba_reset) - return -EACCES; - spin_lock_irq(&phba->hbalock); - if (phba->over_temp_state == HBA_OVER_TEMP) { - spin_unlock_irq(&phba->hbalock); - return -EACCES; - } - spin_unlock_irq(&phba->hbalock); - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if (!phba->soft_wwn_enable) - return -EINVAL; - - /* lock setting wwpn, wwnn down */ - phba->soft_wwn_enable = 0; - - rc = lpfc_wwn_set(buf, cnt, wwpn); - if (!rc) { - /* not able to set wwpn, unlock it */ - phba->soft_wwn_enable = 1; - return rc; - } - - phba->cfg_soft_wwpn = wwn_to_u64(wwpn); - fc_host_port_name(shost) = phba->cfg_soft_wwpn; - if (phba->cfg_soft_wwnn) - fc_host_node_name(shost) = phba->cfg_soft_wwnn; - - dev_printk(KERN_NOTICE, &phba->pcidev->dev, - "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no); - - stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - if (stat1) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0463 lpfc_soft_wwpn attribute set failed to " - "reinit adapter - %d\n", stat1); - init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &stat2, &online_compl, - LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; - - wait_for_completion(&online_compl); - if (stat2) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0464 lpfc_soft_wwpn attribute set failed to " - "reinit adapter - %d\n", stat2); - return (stat1 || stat2) ? -EIO : count; -} -static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR, - lpfc_soft_wwpn_show, lpfc_soft_wwpn_store); - -/** - * lpfc_soft_wwnn_show - Return the cfg soft ww node name for the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the wwnn in hexadecimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return snprintf(buf, PAGE_SIZE, "0x%llx\n", - (unsigned long long)phba->cfg_soft_wwnn); -} - -/** - * lpfc_soft_wwnn_store - sets the ww node name of the adapter - * @cdev: class device that is converted into a Scsi_host. - * @buf: contains the ww node name in hexadecimal. - * @count: number of wwnn bytes in buf. - * - * Returns: - * -EINVAL soft wwn not enabled, count is invalid, invalid wwnn byte invalid - * value of count on success - **/ -static ssize_t -lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - unsigned int cnt = count; - u8 wwnn[WWN_SZ]; - int rc; - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if (!phba->soft_wwn_enable) - return -EINVAL; - - rc = lpfc_wwn_set(buf, cnt, wwnn); - if (!rc) { - /* Allow wwnn to be set many times, as long as the enable - * is set. However, once the wwpn is set, everything locks. - */ - return rc; - } - - phba->cfg_soft_wwnn = wwn_to_u64(wwnn); - - dev_printk(KERN_NOTICE, &phba->pcidev->dev, - "lpfc%d: soft_wwnn set. Value will take effect upon " - "setting of the soft_wwpn\n", phba->brd_no); - - return count; -} -static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR, - lpfc_soft_wwnn_show, lpfc_soft_wwnn_store); /** * lpfc_oas_tgt_show - Return wwpn of target whose luns maybe enabled for @@ -4750,9 +4539,6 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_fcp_cpu_map, &dev_attr_lpfc_fcp_io_channel, &dev_attr_lpfc_enable_bg, - &dev_attr_lpfc_soft_wwnn, - &dev_attr_lpfc_soft_wwpn, - &dev_attr_lpfc_soft_wwn_enable, &dev_attr_lpfc_enable_hba_reset, &dev_attr_lpfc_enable_hba_heartbeat, &dev_attr_lpfc_EnableXLane, @@ -5765,8 +5551,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) else phba->cfg_poll = lpfc_poll; - phba->cfg_soft_wwnn = 0L; - phba->cfg_soft_wwpn = 0L; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4776fd85514f..43d2b06bdc82 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -319,36 +319,26 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) /** * lpfc_update_vport_wwn - Updates the fc_nodename, fc_portname, - * cfg_soft_wwnn, cfg_soft_wwpn * @vport: pointer to lpfc vport data structure. * - * * Return codes * None. **/ void lpfc_update_vport_wwn(struct lpfc_vport *vport) { - /* If the soft name exists then update it using the service params */ - if (vport->phba->cfg_soft_wwnn) - u64_to_wwn(vport->phba->cfg_soft_wwnn, - vport->fc_sparam.nodeName.u.wwn); - if (vport->phba->cfg_soft_wwpn) - u64_to_wwn(vport->phba->cfg_soft_wwpn, - vport->fc_sparam.portName.u.wwn); - /* - * If the name is empty or there exists a soft name + * If the name is empty * then copy the service params name, otherwise use the fc name */ - if (vport->fc_nodename.u.wwn[0] == 0 || vport->phba->cfg_soft_wwnn) + if (vport->fc_nodename.u.wwn[0] == 0) memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, sizeof(struct lpfc_name)); else memcpy(&vport->fc_sparam.nodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); - if (vport->fc_portname.u.wwn[0] == 0 || vport->phba->cfg_soft_wwpn) + if (vport->fc_portname.u.wwn[0] == 0) memcpy(&vport->fc_portname, &vport->fc_sparam.portName, sizeof(struct lpfc_name)); else From e6c6acc0e0223ddaf867628d420ee196349c6fae Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:23 -0800 Subject: [PATCH 0203/1587] scsi: lpfc: Correct issue leading to oops during link reset Correct issue leading to oops during link reset. Missing vport pointer. [mkp: fixed typo] Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index f895cb9c89a3..6b75a8fced33 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -10029,6 +10029,7 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt->ulpCommand = CMD_CLOSE_XRI_CN; abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; + abtsiocbp->vport = vport; lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, "0339 Abort xri x%x, original iotag x%x, " From 6c9231f604c2575be24c96d38deb70f145172f92 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:24 -0800 Subject: [PATCH 0204/1587] scsi: lpfc: Correct host name in symbolic_name field Correct host name in symbolic_name field of nameserver registrations Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 98c40a734a36..f3250ad6b3eb 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -4846,6 +4846,19 @@ lpfc_free_sysfs_attr(struct lpfc_vport *vport) * Dynamic FC Host Attributes Support */ +/** + * lpfc_get_host_symbolic_name - Copy symbolic name into the scsi host + * @shost: kernel scsi host pointer. + **/ +static void +lpfc_get_host_symbolic_name(struct Scsi_Host *shost) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + + lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost), + sizeof fc_host_symbolic_name(shost)); +} + /** * lpfc_get_host_port_id - Copy the vport DID into the scsi host port id * @shost: kernel scsi host pointer. @@ -5383,6 +5396,8 @@ struct fc_function_template lpfc_transport_functions = { .show_host_supported_fc4s = 1, .show_host_supported_speeds = 1, .show_host_maxframe_size = 1, + + .get_host_symbolic_name = lpfc_get_host_symbolic_name, .show_host_symbolic_name = 1, /* dynamic attributes the driver supports */ @@ -5450,6 +5465,8 @@ struct fc_function_template lpfc_vport_transport_functions = { .show_host_supported_fc4s = 1, .show_host_supported_speeds = 1, .show_host_maxframe_size = 1, + + .get_host_symbolic_name = lpfc_get_host_symbolic_name, .show_host_symbolic_name = 1, /* dynamic attributes the driver supports */ From 104450eb08ca662e6b1d02da11aca9598e978f3e Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:25 -0800 Subject: [PATCH 0205/1587] scsi: lpfc: FCoE VPort enable-disable does not bring up the VPort FCoE VPort enable-disable does not bring up the VPort. VPI structure needed to be initialized before being re-registered. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_vport.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index c27f4b724547..e18bbc66e83b 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -537,6 +537,12 @@ enable_vport(struct fc_vport *fc_vport) spin_lock_irq(shost->host_lock); vport->load_flag |= FC_LOADING; + if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) { + spin_unlock_irq(shost->host_lock); + lpfc_issue_init_vpi(vport); + goto out; + } + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); @@ -557,6 +563,8 @@ enable_vport(struct fc_vport *fc_vport) } else { lpfc_vport_set_state(vport, FC_VPORT_FAILED); } + +out: lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, "1827 Vport Enabled.\n"); return VPORT_OK; From b5749fe182a0fa1c39ea1b33c0691d436f269195 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:26 -0800 Subject: [PATCH 0206/1587] scsi: lpfc: Fix Xlane dynamic LUN set for LUN priority. Fix Xlane dynamic LUN set for LUN priority. Dynamic changing of the priority was not getting reflected on the LUN. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 23 +++++++++++++++-------- drivers/scsi/lpfc/lpfc_crtn.h | 7 ++++--- drivers/scsi/lpfc/lpfc_scsi.c | 18 ++++++++++++------ 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index f3250ad6b3eb..c30fafe3bb31 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -2224,7 +2224,8 @@ lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr, else phba->cfg_oas_flags &= ~OAS_FIND_ANY_VPORT; phba->cfg_oas_flags &= ~OAS_LUN_VALID; - phba->cfg_oas_priority = phba->cfg_XLanePriority; + if (phba->cfg_oas_priority == 0) + phba->cfg_oas_priority = phba->cfg_XLanePriority; phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN; return count; } @@ -2350,7 +2351,7 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], rc = -ENOMEM; } else { lpfc_disable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn, - (struct lpfc_name *)tgt_wwpn, lun); + (struct lpfc_name *)tgt_wwpn, lun, pri); } return rc; @@ -2374,7 +2375,8 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], */ static uint64_t lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[], - uint8_t tgt_wwpn[], uint32_t *lun_status) + uint8_t tgt_wwpn[], uint32_t *lun_status, + uint32_t *lun_pri) { uint64_t found_lun; @@ -2387,7 +2389,7 @@ lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[], &phba->sli4_hba.oas_next_lun, (struct lpfc_name *)vpt_wwpn, (struct lpfc_name *)tgt_wwpn, - &found_lun, lun_status)) + &found_lun, lun_status, lun_pri)) return found_lun; else return NOT_OAS_ENABLED_LUN; @@ -2459,7 +2461,8 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr, oas_lun = lpfc_oas_lun_get_next(phba, phba->cfg_oas_vpt_wwpn, phba->cfg_oas_tgt_wwpn, - &phba->cfg_oas_lun_status); + &phba->cfg_oas_lun_status, + &phba->cfg_oas_priority); if (oas_lun != NOT_OAS_ENABLED_LUN) phba->cfg_oas_flags |= OAS_LUN_VALID; @@ -2490,6 +2493,7 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; uint64_t scsi_lun; + uint32_t pri; ssize_t rc; if (!phba->cfg_fof) @@ -2507,17 +2511,20 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, if (sscanf(buf, "0x%llx", &scsi_lun) != 1) return -EINVAL; + pri = phba->cfg_oas_priority; + if (pri == 0) + pri = phba->cfg_XLanePriority; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3372 Try to set vport 0x%llx target 0x%llx lun:0x%llx " "priority 0x%x with oas state %d\n", wwn_to_u64(phba->cfg_oas_vpt_wwpn), wwn_to_u64(phba->cfg_oas_tgt_wwpn), scsi_lun, - phba->cfg_oas_priority, phba->cfg_oas_lun_state); + pri, phba->cfg_oas_lun_state); rc = lpfc_oas_lun_state_change(phba, phba->cfg_oas_vpt_wwpn, phba->cfg_oas_tgt_wwpn, scsi_lun, - phba->cfg_oas_lun_state, - phba->cfg_oas_priority); + phba->cfg_oas_lun_state, pri); if (rc) return rc; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 15d2bfdf582d..309643a2c55c 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -480,7 +480,7 @@ void lpfc_sli4_offline_eratt(struct lpfc_hba *); struct lpfc_device_data *lpfc_create_device_data(struct lpfc_hba *, struct lpfc_name *, struct lpfc_name *, - uint64_t, bool); + uint64_t, uint32_t, bool); void lpfc_delete_device_data(struct lpfc_hba *, struct lpfc_device_data*); struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *, struct list_head *list, @@ -489,9 +489,10 @@ struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *, bool lpfc_enable_oas_lun(struct lpfc_hba *, struct lpfc_name *, struct lpfc_name *, uint64_t, uint8_t); bool lpfc_disable_oas_lun(struct lpfc_hba *, struct lpfc_name *, - struct lpfc_name *, uint64_t); + struct lpfc_name *, uint64_t, uint8_t); bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *, struct lpfc_name *, uint64_t *, struct lpfc_name *, - struct lpfc_name *, uint64_t *, uint32_t *); + struct lpfc_name *, uint64_t *, + uint32_t *, uint32_t *); int lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox); void lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index ad350d969bdc..19d349fc889f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5452,7 +5452,9 @@ lpfc_slave_alloc(struct scsi_device *sdev) device_data = lpfc_create_device_data(phba, &vport->fc_portname, &target_wwpn, - sdev->lun, true); + sdev->lun, + phba->cfg_XLanePriority, + true); if (!device_data) return -ENOMEM; spin_lock_irqsave(&phba->devicelock, flags); @@ -5587,7 +5589,7 @@ lpfc_slave_destroy(struct scsi_device *sdev) struct lpfc_device_data* lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct lpfc_name *target_wwpn, uint64_t lun, - bool atomic_create) + uint32_t pri, bool atomic_create) { struct lpfc_device_data *lun_info; @@ -5614,7 +5616,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, sizeof(struct lpfc_name)); lun_info->device_id.lun = lun; lun_info->oas_enabled = false; - lun_info->priority = phba->cfg_XLanePriority; + lun_info->priority = pri; lun_info->available = false; return lun_info; } @@ -5716,7 +5718,8 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct lpfc_name *found_vport_wwpn, struct lpfc_name *found_target_wwpn, uint64_t *found_lun, - uint32_t *found_lun_status) + uint32_t *found_lun_status, + uint32_t *found_lun_pri) { unsigned long flags; @@ -5763,6 +5766,7 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, OAS_LUN_STATUS_EXISTS; else *found_lun_status = 0; + *found_lun_pri = lun_info->priority; if (phba->cfg_oas_flags & OAS_FIND_ANY_VPORT) memset(vport_wwpn, 0x0, sizeof(struct lpfc_name)); @@ -5824,13 +5828,14 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, if (lun_info) { if (!lun_info->oas_enabled) lun_info->oas_enabled = true; + lun_info->priority = pri; spin_unlock_irqrestore(&phba->devicelock, flags); return true; } /* Create an lun info structure and add to list of luns */ lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun, - false); + pri, false); if (lun_info) { lun_info->oas_enabled = true; lun_info->priority = pri; @@ -5864,7 +5869,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, **/ bool lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, - struct lpfc_name *target_wwpn, uint64_t lun) + struct lpfc_name *target_wwpn, uint64_t lun, uint8_t pri) { struct lpfc_device_data *lun_info; @@ -5882,6 +5887,7 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, target_wwpn, lun); if (lun_info) { lun_info->oas_enabled = false; + lun_info->priority = pri; if (!lun_info->available) lpfc_delete_device_data(phba, lun_info); spin_unlock_irqrestore(&phba->devicelock, flags); From f2bf460cf5ef989f0a593d05932460326376d5f6 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:27 -0800 Subject: [PATCH 0207/1587] scsi: lpfc: Deprecate lpfc_prot_sg_seg_cnt parameter Deprecate lpfc_prot_sg_seg_cnt parameter. Eliminates driver from unnecessarily limiting DIF s/g list length. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 - drivers/scsi/lpfc/lpfc_attr.c | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 341b656e9d9d..c2e6ffd2f372 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -727,7 +727,6 @@ struct lpfc_hba { uint32_t cfg_fcp_io_channel; uint32_t cfg_total_seg_cnt; uint32_t cfg_sg_seg_cnt; - uint32_t cfg_prot_sg_seg_cnt; uint32_t cfg_sg_dma_buf_size; uint32_t cfg_hba_queue_depth; uint32_t cfg_enable_hba_reset; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c30fafe3bb31..8301c08b8768 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -4465,14 +4465,6 @@ LPFC_ATTR(delay_discovery, 0, 0, 1, LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count"); -/* - * This parameter will be depricated, the driver cannot limit the - * protection data s/g list. - */ -LPFC_ATTR_R(prot_sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, - LPFC_DEFAULT_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT, - "Max Protection Scatter Gather Segment Count"); - /* * lpfc_enable_mds_diags: Enable MDS Diagnostics * 0 = MDS Diagnostics disabled (default) @@ -4559,7 +4551,6 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_sg_seg_cnt, &dev_attr_lpfc_max_scsicmpl_time, &dev_attr_lpfc_stat_data_ctrl, - &dev_attr_lpfc_prot_sg_seg_cnt, &dev_attr_lpfc_aer_support, &dev_attr_lpfc_aer_state_cleanup, &dev_attr_lpfc_sriov_nr_virtfn, @@ -5576,7 +5567,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_poll = lpfc_poll; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); - lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); lpfc_aer_support_init(phba, lpfc_aer_support); From 2f07784f05c23b322863274e801c31aa64e46c71 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:29 -0800 Subject: [PATCH 0208/1587] scsi: lpfc: Correct oops on vport port resets Correct oops on vport port resets. Incorrect WQE type, thus the clearing code actually overstepped the WQE. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 6b75a8fced33..7e11cbdb238c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -17221,7 +17221,8 @@ lpfc_drain_txq(struct lpfc_hba *phba) unsigned long iflags = 0; char *fail_msg = NULL; struct lpfc_sglq *sglq; - union lpfc_wqe wqe; + union lpfc_wqe128 wqe128; + union lpfc_wqe *wqe = (union lpfc_wqe *) &wqe128; uint32_t txq_cnt = 0; spin_lock_irqsave(&pring->ring_lock, iflags); @@ -17260,9 +17261,9 @@ lpfc_drain_txq(struct lpfc_hba *phba) piocbq->sli4_xritag = sglq->sli4_xritag; if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq)) fail_msg = "to convert bpl to sgl"; - else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe)) + else if (lpfc_sli4_iocb2wqe(phba, piocbq, wqe)) fail_msg = "to convert iocb to wqe"; - else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) + else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, wqe)) fail_msg = " - Wq is full"; else lpfc_sli_ringtxcmpl_put(phba, pring, piocbq); From 6b3b3bdb83b4ad51252d21bb13596db879e51850 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:30 -0800 Subject: [PATCH 0209/1587] scsi: lpfc: Add missing memory barrier On loosely ordered memory systems (PPC for example), the WQE elements were being updated in memory, but not necessarily flushed before the separate doorbell was written to hw which would cause hw to dma the WQE element. Thus, the hardware occasionally received partially updated WQE data. Add the memory barrier after updating the WQE memory. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 7e11cbdb238c..3a8470d55af5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -120,6 +120,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size); + /* ensure WQE bcopy flushed before doorbell write */ + wmb(); /* Update the host index before invoking device */ host_index = q->host_index; From 4b089d18ed979d91424355b117070f2520f85aeb Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 19 Dec 2016 15:07:31 -0800 Subject: [PATCH 0210/1587] scsi: lpfc: lpfc version change to 11.2.0.4 lpfc version change to 11.2.0.4 Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 50bfc43ebcb0..0ee0623a354c 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "11.2.0.2" +#define LPFC_DRIVER_VERSION "11.2.0.4" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ From 93380123fbb5357d3ea6935efc9226df3c59099d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Dec 2016 17:04:49 -0800 Subject: [PATCH 0211/1587] scsi: hpsa: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Acked-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.h | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 64e98295b707..bf6cdc106654 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -578,38 +578,38 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) } static struct access_method SA5_access = { - SA5_submit_command, - SA5_intr_mask, - SA5_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_intr_mask, + .intr_pending = SA5_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5_ioaccel_mode1_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_ioaccel_mode1_intr_pending, - SA5_ioaccel_mode1_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_ioaccel_mode1_intr_pending, + .command_completed = SA5_ioaccel_mode1_completed, }; static struct access_method SA5_ioaccel_mode2_access = { - SA5_submit_command_ioaccel2, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command_ioaccel2, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; static struct access_method SA5_performant_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; static struct access_method SA5_performant_access_no_read = { - SA5_submit_command_no_read, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command_no_read, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; struct board_type { From 5f5fca6db3d3e6a2c1a2ae92cbecee50e1242a3a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Dec 2016 17:05:30 -0800 Subject: [PATCH 0212/1587] scsi: cciss: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/block/cciss.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 7fda30e4a241..428766d1ce80 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -402,27 +402,27 @@ static bool SA5_performant_intr_pending(ctlr_info_t *h) } static struct access_method SA5_access = { - SA5_submit_command, - SA5_intr_mask, - SA5_fifo_full, - SA5_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5B_access = { - SA5_submit_command, - SA5B_intr_mask, - SA5_fifo_full, - SA5B_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5B_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5B_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5_performant_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_fifo_full, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; struct board_type { From e0075478ca7c58c6ad6630310aaa3f64a25dcf31 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 15 Dec 2016 15:12:16 +0100 Subject: [PATCH 0213/1587] scsi: mptlan: Remove linux/miscdevice.h from mptlan.h This patch remove linux/miscdevice.h from mptlan.h since mptlan.h does not contain any miscdevice. The only user of it is mptctl.c which already include linux/miscdevice.h So no need to include it twice. Signed-off-by: Corentin Labbe Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptlan.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index 8946e19dbfc8..8a24494f8c4d 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -65,7 +65,6 @@ #include #include #include -#include #include #include #include From 19099dc393f3ca1fd9690f914e50278cf2aee78a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 16 Dec 2016 12:35:39 +0300 Subject: [PATCH 0214/1587] scsi: dpt_i2o: double free if adpt_i2o_online_hba() fails There are two places where adpt_i2o_online_hba() is called. Both callers call adpt_i2o_delete_hba(pHba) if adpt_i2o_online_hba() fails and since we also free it here that causes a double free bug. Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/dpt_i2o.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 5f75e638ec95..256dd6791fcc 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -2768,16 +2768,12 @@ static int adpt_i2o_activate_hba(adpt_hba* pHba) static int adpt_i2o_online_hba(adpt_hba* pHba) { - if (adpt_i2o_systab_send(pHba) < 0) { - adpt_i2o_delete_hba(pHba); + if (adpt_i2o_systab_send(pHba) < 0) return -1; - } /* In READY state */ - if (adpt_i2o_enable_hba(pHba) < 0) { - adpt_i2o_delete_hba(pHba); + if (adpt_i2o_enable_hba(pHba) < 0) return -1; - } /* In OPERATIONAL state */ return 0; From f3505013779646704f81b41c011ab089b26c3f3e Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:55:54 +0530 Subject: [PATCH 0215/1587] scsi: be2iscsi: Fix use of invalidate command table req Remove shared structure inv_tbl in phba for all sessions to post invalidation IOCTL. Always allocate and then free the table after use in reset handler. Abort handler needs just one instance so define it on stack. Add checks for BE_INVLDT_CMD_TBL_SZ to not exceed invalidation command table size in IOCTL. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 85 +++++++++++++++++++-------------- drivers/scsi/be2iscsi/be_main.h | 16 +++---- drivers/scsi/be2iscsi/be_mgmt.c | 12 +++-- drivers/scsi/be2iscsi/be_mgmt.h | 40 ++++++++-------- 4 files changed, 83 insertions(+), 70 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b5112d6d7e73..3811a0d230f2 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -225,9 +225,9 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) struct beiscsi_conn *beiscsi_conn; struct beiscsi_hba *phba; struct iscsi_session *session; - struct invalidate_command_table *inv_tbl; + struct invldt_cmd_tbl inv_tbl; struct be_dma_mem nonemb_cmd; - unsigned int cid, tag, num_invalidate; + unsigned int cid, tag; int rc; cls_session = starget_to_session(scsi_target(sc->device)); @@ -247,35 +247,30 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) return SUCCESS; } spin_unlock_bh(&session->frwd_lock); - /* Invalidate WRB Posted for this Task */ - AMAP_SET_BITS(struct amap_iscsi_wrb, invld, - aborted_io_task->pwrb_handle->pwrb, - 1); conn = aborted_task->conn; beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; - + /* Invalidate WRB Posted for this Task */ + AMAP_SET_BITS(struct amap_iscsi_wrb, invld, + aborted_io_task->pwrb_handle->pwrb, + 1); /* invalidate iocb */ cid = beiscsi_conn->beiscsi_conn_cid; - inv_tbl = phba->inv_tbl; - memset(inv_tbl, 0x0, sizeof(*inv_tbl)); - inv_tbl->cid = cid; - inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index; - num_invalidate = 1; - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, - sizeof(struct invalidate_commands_params_in), - &nonemb_cmd.dma); + inv_tbl.cid = cid; + inv_tbl.icd = aborted_io_task->psgl_handle->sgl_index; + nonemb_cmd.size = sizeof(union be_invldt_cmds_params); + nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, + nonemb_cmd.size, + &nonemb_cmd.dma); if (nonemb_cmd.va == NULL) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, "BM_%d : Failed to allocate memory for" "mgmt_invalidate_icds\n"); return FAILED; } - nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); - tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, - cid, &nonemb_cmd); + tag = mgmt_invalidate_icds(phba, &inv_tbl, 1, cid, &nonemb_cmd); if (!tag) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, "BM_%d : mgmt_invalidate_icds could not be" @@ -303,10 +298,10 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) struct beiscsi_hba *phba; struct iscsi_session *session; struct iscsi_cls_session *cls_session; - struct invalidate_command_table *inv_tbl; + struct invldt_cmd_tbl *inv_tbl; struct be_dma_mem nonemb_cmd; - unsigned int cid, tag, i, num_invalidate; - int rc; + unsigned int cid, tag, i, nents; + int rc, more = 0; /* invalidate iocbs */ cls_session = starget_to_session(scsi_target(sc->device)); @@ -320,9 +315,15 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; cid = beiscsi_conn->beiscsi_conn_cid; - inv_tbl = phba->inv_tbl; - memset(inv_tbl, 0x0, sizeof(*inv_tbl) * BE2_CMDS_PER_CXN); - num_invalidate = 0; + + inv_tbl = kcalloc(BE_INVLDT_CMD_TBL_SZ, sizeof(*inv_tbl), GFP_KERNEL); + if (!inv_tbl) { + spin_unlock_bh(&session->frwd_lock); + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, + "BM_%d : invldt_cmd_tbl alloc failed\n"); + return FAILED; + } + nents = 0; for (i = 0; i < conn->session->cmds_max; i++) { abrt_task = conn->session->cmds[i]; abrt_io_task = abrt_task->dd_data; @@ -331,33 +332,47 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) if (sc->device->lun != abrt_task->sc->device->lun) continue; + /** + * Can't fit in more cmds? Normally this won't happen b'coz + * BEISCSI_CMD_PER_LUN is same as BE_INVLDT_CMD_TBL_SZ. + */ + if (nents == BE_INVLDT_CMD_TBL_SZ) { + more = 1; + break; + } /* Invalidate WRB Posted for this Task */ AMAP_SET_BITS(struct amap_iscsi_wrb, invld, abrt_io_task->pwrb_handle->pwrb, 1); - inv_tbl->cid = cid; - inv_tbl->icd = abrt_io_task->psgl_handle->sgl_index; - num_invalidate++; - inv_tbl++; + inv_tbl[nents].cid = cid; + inv_tbl[nents].icd = abrt_io_task->psgl_handle->sgl_index; + nents++; } spin_unlock_bh(&session->frwd_lock); - inv_tbl = phba->inv_tbl; - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, - sizeof(struct invalidate_commands_params_in), - &nonemb_cmd.dma); + if (more) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, + "BM_%d : number of cmds exceeds size of invalidation table\n"); + kfree(inv_tbl); + return FAILED; + } + + nonemb_cmd.size = sizeof(union be_invldt_cmds_params); + nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, + nonemb_cmd.size, + &nonemb_cmd.dma); if (nonemb_cmd.va == NULL) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, "BM_%d : Failed to allocate memory for" "mgmt_invalidate_icds\n"); + kfree(inv_tbl); return FAILED; } - nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); - memset(nonemb_cmd.va, 0, nonemb_cmd.size); - tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, + tag = mgmt_invalidate_icds(phba, inv_tbl, nents, cid, &nonemb_cmd); + kfree(inv_tbl); if (!tag) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, "BM_%d : mgmt_invalidate_icds could not be" diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 6376657e45f7..f869e3734c02 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -57,7 +57,6 @@ #define BE2_IO_DEPTH 1024 #define BE2_MAX_SESSIONS 256 -#define BE2_CMDS_PER_CXN 128 #define BE2_TMFS 16 #define BE2_NOPOUT_REQ 16 #define BE2_SGE 32 @@ -72,8 +71,13 @@ #define BEISCSI_SGLIST_ELEMENTS 30 -#define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ -#define BEISCSI_MAX_SECTORS 1024 /* scsi_host->max_sectors */ +/** + * BE_INVLDT_CMD_TBL_SZ is 128 which is total number commands that can + * be invalidated at a time, consider it before changing the value of + * BEISCSI_CMD_PER_LUN. + */ +#define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ +#define BEISCSI_MAX_SECTORS 1024 /* scsi_host->max_sectors */ #define BEISCSI_TEMPLATE_HDR_PER_CXN_SIZE 128 /* Template size per cxn */ #define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */ @@ -272,11 +276,6 @@ struct hba_parameters { unsigned int num_sge; }; -struct invalidate_command_table { - unsigned short icd; - unsigned short cid; -} __packed; - #define BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cri) \ (phwi_ctrlr->wrb_context[cri].ulp_num) struct hwi_wrb_context { @@ -430,7 +429,6 @@ struct beiscsi_hba { struct be_ctrl_info ctrl; unsigned int generation; unsigned int interface_handle; - struct invalidate_command_table inv_tbl[128]; struct be_aic_obj aic_obj[MAX_CPUS]; unsigned int attr_log_enable; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index ac05317bba7f..5f02e8db7df0 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -129,7 +129,7 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, } unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invalidate_command_table *inv_tbl, + struct invldt_cmd_tbl *inv_tbl, unsigned int num_invalidate, unsigned int cid, struct be_dma_mem *nonemb_cmd) @@ -137,9 +137,12 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; struct be_sge *sge; - struct invalidate_commands_params_in *req; + struct invldt_cmds_params_in *req; unsigned int i, tag; + if (num_invalidate > BE_INVLDT_CMD_TBL_SZ) + return 0; + mutex_lock(&ctrl->mbox_lock); wrb = alloc_mcc_wrb(phba, &tag); if (!wrb) { @@ -158,10 +161,9 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, req->ref_handle = 0; req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; for (i = 0; i < num_invalidate; i++) { - req->table[i].icd = inv_tbl->icd; - req->table[i].cid = inv_tbl->cid; + req->table[i].icd = inv_tbl[i].icd; + req->table[i].cid = inv_tbl[i].cid; req->icd_count++; - inv_tbl++; } sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index b897cfd57c72..6e19281b9d57 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -104,10 +104,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba, unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned int upload_flag); -unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invalidate_command_table *inv_tbl, - unsigned int num_invalidate, unsigned int cid, - struct be_dma_mem *nonemb_cmd); unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba, struct bsg_job *job, @@ -134,24 +130,31 @@ union iscsi_invalidate_connection_params { struct iscsi_invalidate_connection_params_out response; } __packed; -struct invalidate_commands_params_in { +#define BE_INVLDT_CMD_TBL_SZ 128 +struct invldt_cmd_tbl { + unsigned short icd; + unsigned short cid; +} __packed; + +struct invldt_cmds_params_in { struct be_cmd_req_hdr hdr; unsigned int ref_handle; unsigned int icd_count; - struct invalidate_command_table table[128]; + struct invldt_cmd_tbl table[BE_INVLDT_CMD_TBL_SZ]; unsigned short cleanup_type; unsigned short unused; } __packed; -struct invalidate_commands_params_out { +struct invldt_cmds_params_out { + struct be_cmd_resp_hdr hdr; unsigned int ref_handle; unsigned int icd_count; - unsigned int icd_status[128]; + unsigned int icd_status[BE_INVLDT_CMD_TBL_SZ]; } __packed; -union invalidate_commands_params { - struct invalidate_commands_params_in request; - struct invalidate_commands_params_out response; +union be_invldt_cmds_params { + struct invldt_cmds_params_in request; + struct invldt_cmds_params_out response; } __packed; struct mgmt_hba_attributes { @@ -231,16 +234,6 @@ struct be_bsg_vendor_cmd { #define GET_MGMT_CONTROLLER_WS(phba) (phba->pmgmt_ws) -/* MGMT CMD flags */ - -#define MGMT_CMDH_FREE (1<<0) - -/* --- MGMT_ERROR_CODES --- */ -/* Error Codes returned in the status field of the CMD response header */ -#define MGMT_STATUS_SUCCESS 0 /* The CMD completed without errors */ -#define MGMT_STATUS_FAILED 1 /* Error status in the Status field of */ - /* the CMD_RESPONSE_HEADER */ - #define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\ pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ bus_address.u.a32.address_lo; \ @@ -265,6 +258,11 @@ struct beiscsi_endpoint { u16 cid_vld; }; +unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, + struct invldt_cmd_tbl *inv_tbl, + unsigned int num_invalidate, unsigned int cid, + struct be_dma_mem *nonemb_cmd); + unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, struct beiscsi_endpoint *beiscsi_ep, unsigned short cid, From 987132167f4bfb132cd56601f77d2bd5ba9cff4a Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:55:55 +0530 Subject: [PATCH 0216/1587] scsi: be2iscsi: Fix for crash in beiscsi_eh_device_reset System crashes when sg_reset is executed in a loop. CPU: 13 PID: 7073 Comm: sg_reset Tainted: G E 4.8.0-rc1+ #4 RIP: 0010:[] [] beiscsi_eh_device_reset+0x160/0x520 [be2iscsi] Call Trace: [] ? scsi_host_alloc_command+0x47/0xc0 [] scsi_try_bus_device_reset+0x2a/0x50 [] scsi_ioctl_reset+0x13e/0x260 [] scsi_ioctl+0x137/0x3d0 [] sg_ioctl+0x572/0xc20 [sg] [] do_vfs_ioctl+0xa7/0x5d0 The accesses to beiscsi_io_task is being protected in device reset handler with frwd_lock but the freeing of task can happen under back_lock. Hold the reference of iscsi_task till invalidation completes. This prevents use of ICD when invalidation of that ICD is being processed. Use frwd_lock for iscsi_tasks looping and back_lock to access beiscsi_io_task structures. Rewrite mgmt_invalidation_icds to handle allocation and freeing of IOCTL buffer in one place. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 123 +++++++++++++------------------- drivers/scsi/be2iscsi/be_mgmt.c | 107 +++++++++++++++------------ drivers/scsi/be2iscsi/be_mgmt.h | 8 +-- 3 files changed, 115 insertions(+), 123 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 3811a0d230f2..7feecc0b4903 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -226,8 +226,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) struct beiscsi_hba *phba; struct iscsi_session *session; struct invldt_cmd_tbl inv_tbl; - struct be_dma_mem nonemb_cmd; - unsigned int cid, tag; + unsigned int cid; int rc; cls_session = starget_to_session(scsi_target(sc->device)); @@ -259,64 +258,47 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) cid = beiscsi_conn->beiscsi_conn_cid; inv_tbl.cid = cid; inv_tbl.icd = aborted_io_task->psgl_handle->sgl_index; - nonemb_cmd.size = sizeof(union be_invldt_cmds_params); - nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, - nonemb_cmd.size, - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, - "BM_%d : Failed to allocate memory for" - "mgmt_invalidate_icds\n"); - return FAILED; - } - - tag = mgmt_invalidate_icds(phba, &inv_tbl, 1, cid, &nonemb_cmd); - if (!tag) { + rc = beiscsi_mgmt_invalidate_icds(phba, &inv_tbl, 1); + if (rc) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, - "BM_%d : mgmt_invalidate_icds could not be" - "submitted\n"); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - + "BM_%d : sc %p invalidation failed %d\n", + sc, rc); return FAILED; } - rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); - if (rc != -EBUSY) - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return iscsi_eh_abort(sc); } static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) { - struct iscsi_task *abrt_task; - struct beiscsi_io_task *abrt_io_task; - struct iscsi_conn *conn; - struct beiscsi_conn *beiscsi_conn; - struct beiscsi_hba *phba; - struct iscsi_session *session; + struct beiscsi_invldt_cmd_tbl { + struct invldt_cmd_tbl tbl[BE_INVLDT_CMD_TBL_SZ]; + struct iscsi_task *task[BE_INVLDT_CMD_TBL_SZ]; + } *inv_tbl; struct iscsi_cls_session *cls_session; - struct invldt_cmd_tbl *inv_tbl; - struct be_dma_mem nonemb_cmd; - unsigned int cid, tag, i, nents; + struct beiscsi_conn *beiscsi_conn; + struct beiscsi_io_task *io_task; + struct iscsi_session *session; + struct beiscsi_hba *phba; + struct iscsi_conn *conn; + struct iscsi_task *task; + unsigned int i, nents; int rc, more = 0; - /* invalidate iocbs */ cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; + spin_lock_bh(&session->frwd_lock); if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) { spin_unlock_bh(&session->frwd_lock); return FAILED; } + conn = session->leadconn; beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; - cid = beiscsi_conn->beiscsi_conn_cid; - inv_tbl = kcalloc(BE_INVLDT_CMD_TBL_SZ, sizeof(*inv_tbl), GFP_KERNEL); + inv_tbl = kzalloc(sizeof(*inv_tbl), GFP_KERNEL); if (!inv_tbl) { spin_unlock_bh(&session->frwd_lock); beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, @@ -324,13 +306,14 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) return FAILED; } nents = 0; + /* take back_lock to prevent task from getting cleaned up under us */ + spin_lock(&session->back_lock); for (i = 0; i < conn->session->cmds_max; i++) { - abrt_task = conn->session->cmds[i]; - abrt_io_task = abrt_task->dd_data; - if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE) + task = conn->session->cmds[i]; + if (!task->sc) continue; - if (sc->device->lun != abrt_task->sc->device->lun) + if (sc->device->lun != task->sc->device->lun) continue; /** * Can't fit in more cmds? Normally this won't happen b'coz @@ -341,52 +324,48 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) break; } - /* Invalidate WRB Posted for this Task */ + /* get a task ref till FW processes the req for the ICD used */ + __iscsi_get_task(task); + io_task = task->dd_data; + /* mark WRB invalid which have been not processed by FW yet */ AMAP_SET_BITS(struct amap_iscsi_wrb, invld, - abrt_io_task->pwrb_handle->pwrb, + io_task->pwrb_handle->pwrb, 1); - inv_tbl[nents].cid = cid; - inv_tbl[nents].icd = abrt_io_task->psgl_handle->sgl_index; + inv_tbl->tbl[nents].cid = beiscsi_conn->beiscsi_conn_cid; + inv_tbl->tbl[nents].icd = io_task->psgl_handle->sgl_index; + inv_tbl->task[nents] = task; nents++; } + spin_unlock_bh(&session->back_lock); spin_unlock_bh(&session->frwd_lock); + rc = SUCCESS; + if (!nents) + goto end_reset; + if (more) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, "BM_%d : number of cmds exceeds size of invalidation table\n"); - kfree(inv_tbl); - return FAILED; + rc = FAILED; + goto end_reset; } - nonemb_cmd.size = sizeof(union be_invldt_cmds_params); - nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, - nonemb_cmd.size, - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, - "BM_%d : Failed to allocate memory for" - "mgmt_invalidate_icds\n"); - kfree(inv_tbl); - return FAILED; - } - tag = mgmt_invalidate_icds(phba, inv_tbl, nents, - cid, &nonemb_cmd); - kfree(inv_tbl); - if (!tag) { + if (beiscsi_mgmt_invalidate_icds(phba, &inv_tbl->tbl[0], nents)) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, - "BM_%d : mgmt_invalidate_icds could not be" - " submitted\n"); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return FAILED; + "BM_%d : cid %u scmds invalidation failed\n", + beiscsi_conn->beiscsi_conn_cid); + rc = FAILED; } - rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); - if (rc != -EBUSY) - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return iscsi_eh_device_reset(sc); +end_reset: + for (i = 0; i < nents; i++) + iscsi_put_task(inv_tbl->task[i]); + kfree(inv_tbl); + + if (rc == SUCCESS) + rc = iscsi_eh_device_reset(sc); + return rc; } /*------------------- PCI Driver operations and data ----------------- */ diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 5f02e8db7df0..110c0d076d9a 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -128,52 +128,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, return tag; } -unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invldt_cmd_tbl *inv_tbl, - unsigned int num_invalidate, unsigned int cid, - struct be_dma_mem *nonemb_cmd) - -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_sge *sge; - struct invldt_cmds_params_in *req; - unsigned int i, tag; - - if (num_invalidate > BE_INVLDT_CMD_TBL_SZ) - return 0; - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return 0; - } - - req = nonemb_cmd->va; - memset(req, 0, sizeof(*req)); - sge = nonembedded_sgl(wrb); - - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, - sizeof(*req)); - req->ref_handle = 0; - req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; - for (i = 0; i < num_invalidate; i++) { - req->table[i].icd = inv_tbl[i].icd; - req->table[i].cid = inv_tbl[i].cid; - req->icd_count++; - } - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd->size); - - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - return tag; -} - unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, struct beiscsi_endpoint *beiscsi_ep, unsigned short cid, @@ -1496,3 +1450,64 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, (params->dw[offsetof(struct amap_beiscsi_offload_params, exp_statsn) / 32] + 1)); } + +int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, + struct invldt_cmd_tbl *inv_tbl, + unsigned int nents) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct invldt_cmds_params_in *req; + struct be_dma_mem nonemb_cmd; + struct be_mcc_wrb *wrb; + unsigned int i, tag; + struct be_sge *sge; + int rc; + + if (!nents || nents > BE_INVLDT_CMD_TBL_SZ) + return -EINVAL; + + nonemb_cmd.size = sizeof(union be_invldt_cmds_params); + nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, + nonemb_cmd.size, + &nonemb_cmd.dma); + if (!nonemb_cmd.va) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, + "BM_%d : invldt_cmds_params alloc failed\n"); + return -ENOMEM; + } + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return -ENOMEM; + } + + req = nonemb_cmd.va; + be_wrb_hdr_prepare(wrb, nonemb_cmd.size, false, 1); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, + sizeof(*req)); + req->ref_handle = 0; + req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; + for (i = 0; i < nents; i++) { + req->table[i].icd = inv_tbl[i].icd; + req->table[i].cid = inv_tbl[i].cid; + req->icd_count++; + } + sge = nonembedded_sgl(wrb); + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); + sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd.dma)); + sge->len = cpu_to_le32(nonemb_cmd.size); + + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + + rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); + if (rc != -EBUSY) + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return rc; +} diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 6e19281b9d57..f301d57320ec 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -258,16 +258,14 @@ struct beiscsi_endpoint { u16 cid_vld; }; -unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invldt_cmd_tbl *inv_tbl, - unsigned int num_invalidate, unsigned int cid, - struct be_dma_mem *nonemb_cmd); - unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, struct beiscsi_endpoint *beiscsi_ep, unsigned short cid, unsigned short issue_reset, unsigned short savecfg_flag); +int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, + struct invldt_cmd_tbl *inv_tbl, + unsigned int nents); int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type); From faa0a22d54230ae9658c419e495fc1a469e191f3 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:55:56 +0530 Subject: [PATCH 0217/1587] scsi: be2iscsi: Take iscsi_task ref in abort handler Hold the reference of iscsi_task till invalidation completes. This prevents use of ICD when invalidation of that ICD is being processed. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 45 ++++++++++++++------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7feecc0b4903..260842a1f14e 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -218,47 +218,40 @@ static int beiscsi_slave_configure(struct scsi_device *sdev) static int beiscsi_eh_abort(struct scsi_cmnd *sc) { + struct iscsi_task *abrt_task = (struct iscsi_task *)sc->SCp.ptr; struct iscsi_cls_session *cls_session; - struct iscsi_task *aborted_task = (struct iscsi_task *)sc->SCp.ptr; - struct beiscsi_io_task *aborted_io_task; - struct iscsi_conn *conn; + struct beiscsi_io_task *abrt_io_task; struct beiscsi_conn *beiscsi_conn; - struct beiscsi_hba *phba; struct iscsi_session *session; struct invldt_cmd_tbl inv_tbl; - unsigned int cid; + struct beiscsi_hba *phba; + struct iscsi_conn *conn; int rc; cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - spin_lock_bh(&session->frwd_lock); - if (!aborted_task || !aborted_task->sc) { - /* we raced */ - spin_unlock_bh(&session->frwd_lock); + /* check if we raced, task just got cleaned up under us */ + spin_lock_bh(&session->back_lock); + if (!abrt_task || !abrt_task->sc) { + spin_unlock_bh(&session->back_lock); return SUCCESS; } - - aborted_io_task = aborted_task->dd_data; - if (!aborted_io_task->scsi_cmnd) { - /* raced or invalid command */ - spin_unlock_bh(&session->frwd_lock); - return SUCCESS; - } - spin_unlock_bh(&session->frwd_lock); - - conn = aborted_task->conn; + /* get a task ref till FW processes the req for the ICD used */ + __iscsi_get_task(abrt_task); + abrt_io_task = abrt_task->dd_data; + conn = abrt_task->conn; beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; - /* Invalidate WRB Posted for this Task */ + /* mark WRB invalid which have been not processed by FW yet */ AMAP_SET_BITS(struct amap_iscsi_wrb, invld, - aborted_io_task->pwrb_handle->pwrb, - 1); - /* invalidate iocb */ - cid = beiscsi_conn->beiscsi_conn_cid; - inv_tbl.cid = cid; - inv_tbl.icd = aborted_io_task->psgl_handle->sgl_index; + abrt_io_task->pwrb_handle->pwrb, 1); + inv_tbl.cid = beiscsi_conn->beiscsi_conn_cid; + inv_tbl.icd = abrt_io_task->psgl_handle->sgl_index; + spin_unlock_bh(&session->back_lock); + rc = beiscsi_mgmt_invalidate_icds(phba, &inv_tbl, 1); + iscsi_put_task(abrt_task); if (rc) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, "BM_%d : sc %p invalidation failed %d\n", From 392b7d2f122210da594671606321223167a5a85c Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:55:57 +0530 Subject: [PATCH 0218/1587] scsi: be2iscsi: Set WRB invalid bit for SkyHawk invalid bit in WRB indicates to FW that IO was invalidated before WRB was fetched from host memory. For SkyHawk, this invalid bit in WRB is at a different offset. Use amap_iscsi_wrb_v2 to mark invalid bit for SkyHawk. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 19 ++++++++++++++----- drivers/scsi/be2iscsi/be_main.h | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 260842a1f14e..b509acd33772 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -244,8 +244,13 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; /* mark WRB invalid which have been not processed by FW yet */ - AMAP_SET_BITS(struct amap_iscsi_wrb, invld, - abrt_io_task->pwrb_handle->pwrb, 1); + if (is_chip_be2_be3r(phba)) { + AMAP_SET_BITS(struct amap_iscsi_wrb, invld, + abrt_io_task->pwrb_handle->pwrb, 1); + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld, + abrt_io_task->pwrb_handle->pwrb, 1); + } inv_tbl.cid = beiscsi_conn->beiscsi_conn_cid; inv_tbl.icd = abrt_io_task->psgl_handle->sgl_index; spin_unlock_bh(&session->back_lock); @@ -321,9 +326,13 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) __iscsi_get_task(task); io_task = task->dd_data; /* mark WRB invalid which have been not processed by FW yet */ - AMAP_SET_BITS(struct amap_iscsi_wrb, invld, - io_task->pwrb_handle->pwrb, - 1); + if (is_chip_be2_be3r(phba)) { + AMAP_SET_BITS(struct amap_iscsi_wrb, invld, + io_task->pwrb_handle->pwrb, 1); + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld, + io_task->pwrb_handle->pwrb, 1); + } inv_tbl->tbl[nents].cid = beiscsi_conn->beiscsi_conn_cid; inv_tbl->tbl[nents].icd = io_task->psgl_handle->sgl_index; diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index f869e3734c02..8ba8c1215922 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -840,7 +840,7 @@ struct amap_iscsi_wrb_v2 { u8 diff_enbl; /* DWORD 11 */ u8 u_run; /* DWORD 11 */ u8 o_run; /* DWORD 11 */ - u8 invalid; /* DWORD 11 */ + u8 invld; /* DWORD 11 */ u8 dsp; /* DWORD 11 */ u8 dmsg; /* DWORD 11 */ u8 rsvd4; /* DWORD 11 */ From 3f7f62ee5b10de42b3ff1a33599fde4a2094960a Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:55:58 +0530 Subject: [PATCH 0219/1587] scsi: be2iscsi: Add checks to validate completions Added check in beiscsi_process_cq for pio_handle. pio_handle is cleared in beiscsi_put_wrb_handle. This catches any case where task gets cleaned up just before completion. Use back_lock before accessing pio_handle. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b509acd33772..832d4f0fb33f 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -960,6 +960,10 @@ beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context, unsigned long flags; spin_lock_irqsave(&pwrb_context->wrb_lock, flags); + if (!pwrb_context->wrb_handles_available) { + spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); + return NULL; + } pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index]; pwrb_context->wrb_handles_available--; if (pwrb_context->alloc_index == (wrbs_per_cxn - 1)) @@ -1010,6 +1014,7 @@ beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context, pwrb_context->free_index = 0; else pwrb_context->free_index++; + pwrb_handle->pio_handle = NULL; spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); } @@ -1220,6 +1225,7 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, uint16_t wrb_index, cid, cri_index; struct hwi_controller *phwi_ctrlr; struct wrb_handle *pwrb_handle; + struct iscsi_session *session; struct iscsi_task *task; phwi_ctrlr = phba->phwi_ctrlr; @@ -1238,8 +1244,12 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, cri_index = BE_GET_CRI_FROM_CID(cid); pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; pwrb_handle = pwrb_context->pwrb_handle_basestd[wrb_index]; + session = beiscsi_conn->conn->session; + spin_lock_bh(&session->back_lock); task = pwrb_handle->pio_handle; - iscsi_put_task(task); + if (task) + __iscsi_put_task(task); + spin_unlock_bh(&session->back_lock); } static void @@ -1319,16 +1329,16 @@ static void adapter_get_sol_cqe(struct beiscsi_hba *phba, static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, struct beiscsi_hba *phba, struct sol_cqe *psol) { - struct hwi_wrb_context *pwrb_context; - struct wrb_handle *pwrb_handle; - struct iscsi_wrb *pwrb = NULL; - struct hwi_controller *phwi_ctrlr; - struct iscsi_task *task; - unsigned int type; struct iscsi_conn *conn = beiscsi_conn->conn; struct iscsi_session *session = conn->session; struct common_sol_cqe csol_cqe = {0}; + struct hwi_wrb_context *pwrb_context; + struct hwi_controller *phwi_ctrlr; + struct wrb_handle *pwrb_handle; + struct iscsi_wrb *pwrb = NULL; + struct iscsi_task *task; uint16_t cri_index = 0; + uint8_t type; phwi_ctrlr = phba->phwi_ctrlr; @@ -1341,11 +1351,15 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, pwrb_handle = pwrb_context->pwrb_handle_basestd[ csol_cqe.wrb_index]; + spin_lock_bh(&session->back_lock); task = pwrb_handle->pio_handle; + if (!task) { + spin_unlock_bh(&session->back_lock); + return; + } pwrb = pwrb_handle->pwrb; type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type; - spin_lock_bh(&session->back_lock); switch (type) { case HWH_TYPE_IO: case HWH_TYPE_IO_RD: From d7401055480d80599b6813fdf556d519ced4d71e Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:55:59 +0530 Subject: [PATCH 0220/1587] scsi: be2iscsi: Fix iSCSI cmd cleanup IOCTL Prepare the IOCTL with appropriate sizes of buffers of V0 and V1. Set missing chute number in V1 IOCTL. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_cmds.c | 33 ++++++++++++++++++--------------- drivers/scsi/be2iscsi/be_main.c | 3 +-- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index be65da2988fb..94aae458489b 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1700,31 +1700,34 @@ int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp) struct be_ctrl_info *ctrl = &phba->ctrl; struct iscsi_cleanup_req_v1 *req_v1; struct iscsi_cleanup_req *req; + u16 hdr_ring_id, data_ring_id; struct be_mcc_wrb *wrb; int status; mutex_lock(&ctrl->mbox_lock); wrb = wrb_from_mbox(&ctrl->mbox_mem); - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); - /** - * TODO: Check with FW folks the chute value to be set. - * For now, use the ULP_MASK as the chute value. - */ + hdr_ring_id = HWI_GET_DEF_HDRQ_ID(phba, ulp); + data_ring_id = HWI_GET_DEF_BUFQ_ID(phba, ulp); if (is_chip_be2_be3r(phba)) { + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); req->chute = (1 << ulp); - req->hdr_ring_id = HWI_GET_DEF_HDRQ_ID(phba, ulp); - req->data_ring_id = HWI_GET_DEF_BUFQ_ID(phba, ulp); + /* BE2/BE3 FW creates 8-bit ring id */ + req->hdr_ring_id = hdr_ring_id; + req->data_ring_id = data_ring_id; } else { - req_v1 = (struct iscsi_cleanup_req_v1 *)req; + req_v1 = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req_v1), true, 0); + be_cmd_hdr_prepare(&req_v1->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_CLEANUP, + sizeof(*req_v1)); req_v1->hdr.version = 1; - req_v1->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba, - ulp)); - req_v1->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba, - ulp)); + req_v1->chute = (1 << ulp); + req_v1->hdr_ring_id = cpu_to_le16(hdr_ring_id); + req_v1->data_ring_id = cpu_to_le16(data_ring_id); } status = be_mbox_notify(ctrl); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 832d4f0fb33f..1b5a07ff93ea 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -2747,7 +2747,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { - /* get async_ctx for each ULP */ + /* get async_ctx for each ULP */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 + (ulp_num * MEM_DESCR_OFFSET)); @@ -3814,7 +3814,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) /** * Now that the default PDU rings have been created, * let EP know about it. - * Call beiscsi_cmd_iscsi_cleanup before posting? */ beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, ulp_num); From b7d98ca7fb476e9f9382445b3a2b973e6c0de3ab Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:56:00 +0530 Subject: [PATCH 0221/1587] scsi: be2iscsi: Remove redundant receive buffers posting This duplicate code got added during manual merging. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1b5a07ff93ea..c6af6e5a23b8 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3859,14 +3859,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) phwi_ctrlr->wrb_context[cri].cid] = async_arr_idx++; } - /** - * Now that the default PDU rings have been created, - * let EP know about it. - */ - beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, - ulp_num); - beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA, - ulp_num); } } From fa1261c4b683828f1b012267aff5b9322fd9ab71 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:56:01 +0530 Subject: [PATCH 0222/1587] scsi: be2iscsi: Remove unused struct members Fix errors reported in static analysis. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be.h | 3 -- drivers/scsi/be2iscsi/be_cmds.c | 8 ++--- drivers/scsi/be2iscsi/be_cmds.h | 17 ++++----- drivers/scsi/be2iscsi/be_iscsi.c | 2 +- drivers/scsi/be2iscsi/be_main.c | 24 +++---------- drivers/scsi/be2iscsi/be_main.h | 22 ------------ drivers/scsi/be2iscsi/be_mgmt.c | 9 ++--- drivers/scsi/be2iscsi/be_mgmt.h | 60 -------------------------------- 8 files changed, 21 insertions(+), 124 deletions(-) diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index b1d0fdc5d5e1..ca9440fb2325 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -84,7 +84,6 @@ static inline void queue_tail_inc(struct be_queue_info *q) /*ISCSI */ struct be_aic_obj { /* Adaptive interrupt coalescing (AIC) info */ - bool enable; u32 min_eqd; /* in usecs */ u32 max_eqd; /* in usecs */ u32 prev_eqd; /* in usecs */ @@ -94,8 +93,6 @@ struct be_aic_obj { /* Adaptive interrupt coalescing (AIC) info */ }; struct be_eq_obj { - bool todo_mcc_cq; - bool todo_cq; u32 cq_count; struct be_queue_info q; struct beiscsi_hba *phba; diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 94aae458489b..5d59e2630ce6 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -676,10 +676,10 @@ void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, bool embedded, u8 sge_cnt) { if (embedded) - wrb->embedded |= MCC_WRB_EMBEDDED_MASK; + wrb->emb_sgecnt_special |= MCC_WRB_EMBEDDED_MASK; else - wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << - MCC_WRB_SGE_CNT_SHIFT; + wrb->emb_sgecnt_special |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << + MCC_WRB_SGE_CNT_SHIFT; wrb->payload_length = payload_len; be_dws_cpu_to_le(wrb, 8); } @@ -1599,7 +1599,7 @@ int beiscsi_cmd_function_reset(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_post_sgl_pages_req *req = embedded_payload(wrb); + struct be_post_sgl_pages_req *req; int status; mutex_lock(&ctrl->mbox_lock); diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 328fb5b973cd..1d40e83b0790 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -31,10 +31,16 @@ struct be_sge { __le32 len; }; -#define MCC_WRB_SGE_CNT_SHIFT 3 /* bits 3 - 7 of dword 0 */ -#define MCC_WRB_SGE_CNT_MASK 0x1F /* bits 3 - 7 of dword 0 */ struct be_mcc_wrb { - u32 embedded; /* dword 0 */ + u32 emb_sgecnt_special; /* dword 0 */ + /* bits 0 - embedded */ + /* bits 1 - 2 reserved */ + /* bits 3 - 7 sge count */ + /* bits 8 - 23 reserved */ + /* bits 24 - 31 special */ +#define MCC_WRB_EMBEDDED_MASK 1 +#define MCC_WRB_SGE_CNT_SHIFT 3 +#define MCC_WRB_SGE_CNT_MASK 0x1F u32 payload_length; /* dword 1 */ u32 tag0; /* dword 2 */ u32 tag1; /* dword 3 */ @@ -1133,11 +1139,6 @@ struct tcp_connect_and_offload_out { } __packed; -struct be_mcc_wrb_context { - struct MCC_WRB *wrb; - int *users_final_status; -} __packed; - #define DB_DEF_PDU_RING_ID_MASK 0x3FFF /* bits 0 - 13 */ #define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 16 - 29 */ #define DB_DEF_PDU_REARM_SHIFT 14 diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index ba258217614e..0ec06256a1b8 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1114,7 +1114,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, nonemb_cmd.size = req_memsize; memset(nonemb_cmd.va, 0, nonemb_cmd.size); tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd); - if (tag <= 0) { + if (!tag) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : mgmt_open_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index c6af6e5a23b8..a8e67c6186f8 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -67,8 +67,6 @@ beiscsi_##_name##_disp(struct device *dev,\ { \ struct Scsi_Host *shost = class_to_shost(dev);\ struct beiscsi_hba *phba = iscsi_host_priv(shost); \ - uint32_t param_val = 0; \ - param_val = phba->attr_##_name;\ return snprintf(buf, PAGE_SIZE, "%d\n",\ phba->attr_##_name);\ } @@ -642,7 +640,6 @@ static void beiscsi_get_params(struct beiscsi_hba *phba) phba->params.num_sge_per_io = BE2_SGE; phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ; - phba->params.eq_timer = 64; phba->params.num_eq_entries = 1024; phba->params.num_cq_entries = 1024; phba->params.wrbs_per_cxn = 256; @@ -1335,7 +1332,6 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, struct hwi_wrb_context *pwrb_context; struct hwi_controller *phwi_ctrlr; struct wrb_handle *pwrb_handle; - struct iscsi_wrb *pwrb = NULL; struct iscsi_task *task; uint16_t cri_index = 0; uint8_t type; @@ -1357,7 +1353,6 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, spin_unlock_bh(&session->back_lock); return; } - pwrb = pwrb_handle->pwrb; type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type; switch (type) { @@ -1721,13 +1716,12 @@ beiscsi_hdq_post_handles(struct beiscsi_hba *phba, struct list_head *hfree_list; struct phys_addr *pasync_sge; u32 ring_id, doorbell = 0; - u16 index, num_entries; u32 doorbell_offset; u16 prod = 0, cons; + u16 index; phwi_ctrlr = phba->phwi_ctrlr; pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); - num_entries = pasync_ctx->num_entries; if (header) { cons = pasync_ctx->async_header.free_entries; hfree_list = &pasync_ctx->async_header.free_list; @@ -2384,13 +2378,10 @@ static int hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task) static void beiscsi_find_mem_req(struct beiscsi_hba *phba) { uint8_t mem_descr_index, ulp_num; - unsigned int num_cq_pages, num_async_pdu_buf_pages; + unsigned int num_async_pdu_buf_pages; unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn; unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages; - num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \ - sizeof(struct sol_cqe)); - phba->params.hwi_ws_sz = sizeof(struct hwi_controller); phba->mem_req[ISCSI_MEM_GLOBAL_HEADER] = 2 * @@ -3377,7 +3368,7 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, struct hwi_context_memory *phwi_context, struct hwi_controller *phwi_ctrlr) { - unsigned int wrb_mem_index, offset, size, num_wrb_rings; + unsigned int num_wrb_rings; u64 pa_addr_lo; unsigned int idx, num, i, ulp_num; struct mem_array *pwrb_arr; @@ -3442,10 +3433,6 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, } for (i = 0; i < phba->params.cxns_per_ctrl; i++) { - wrb_mem_index = 0; - offset = 0; - size = 0; - if (ulp_count > 1) { ulp_base_num = (ulp_base_num + 1) % BEISCSI_ULP_COUNT; @@ -3673,7 +3660,6 @@ static void hwi_cleanup_port(struct beiscsi_hba *phba) struct be_ctrl_info *ctrl = &phba->ctrl; struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; - struct hd_async_context *pasync_ctx; int i, eq_for_mcc, ulp_num; for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) @@ -3710,8 +3696,6 @@ static void hwi_cleanup_port(struct beiscsi_hba *phba) q = &phwi_context->be_def_dataq[ulp_num]; if (q->created) beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); - - pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num]; } } @@ -3937,7 +3921,7 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba) static int beiscsi_init_controller(struct beiscsi_hba *phba) { - int ret = -ENOMEM; + int ret; ret = beiscsi_get_memory(phba); if (ret < 0) { diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 8ba8c1215922..73cc2f775291 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -243,19 +243,7 @@ struct hba_parameters { unsigned int num_cq_entries; unsigned int num_eq_entries; unsigned int wrbs_per_cxn; - unsigned int crashmode; - unsigned int hba_num; - - unsigned int mgmt_ws_sz; unsigned int hwi_ws_sz; - - unsigned int eto; - unsigned int ldto; - - unsigned int dbg_flags; - unsigned int num_cxn; - - unsigned int eq_timer; /** * These are calculated from other params. They're here * for debug purposes @@ -333,7 +321,6 @@ struct beiscsi_hba { struct be_bus_address pci_pa; /* CSR */ /* PCI representation of our HBA */ struct pci_dev *pcidev; - unsigned short asic_revision; unsigned int num_cpus; unsigned int nxt_cqid; struct msix_entry msix_entries[MAX_CPUS]; @@ -354,7 +341,6 @@ struct beiscsi_hba { spinlock_t io_sgl_lock; spinlock_t mgmt_sgl_lock; spinlock_t async_pdu_lock; - unsigned int age; struct list_head hba_queue; #define BE_MAX_SESSION 2048 #define BE_SET_CID_TO_CRI(cri_index, cid) \ @@ -523,10 +509,6 @@ struct beiscsi_io_task { struct scsi_cmnd *scsi_cmnd; int num_sg; struct hwi_wrb_context *pwrb_context; - unsigned int cmd_sn; - unsigned int flags; - unsigned short cid; - unsigned short header_len; itt_t libiscsi_itt; struct be_cmd_bhs *cmd_bhs; struct be_bus_address bhs_pa; @@ -1040,10 +1022,8 @@ struct hwi_controller { struct list_head io_sgl_list; struct list_head eh_sgl_list; struct sgl_handle *psgl_handle_base; - unsigned int wrb_mem_index; struct hwi_wrb_context *wrb_context; - struct mcc_wrb *pmcc_wrb_base; struct be_ring default_pdu_hdr[BEISCSI_ULP_COUNT]; struct be_ring default_pdu_data[BEISCSI_ULP_COUNT]; struct hwi_context_memory *phwi_ctxt; @@ -1060,9 +1040,7 @@ enum hwh_type_enum { }; struct wrb_handle { - enum hwh_type_enum type; unsigned short wrb_index; - struct iscsi_task *pio_handle; struct iscsi_wrb *pwrb; }; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 110c0d076d9a..8acacd5ec796 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -66,7 +66,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, struct bsg_job *job, struct be_dma_mem *nonemb_cmd) { - struct be_cmd_resp_hdr *resp; struct be_mcc_wrb *wrb; struct be_sge *mcc_sge; unsigned int tag = 0; @@ -76,7 +75,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, nonemb_cmd->size = job->request_payload.payload_len; memset(nonemb_cmd->va, 0, nonemb_cmd->size); - resp = nonemb_cmd->va; region = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; sector_size = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; sector = bsg_req->rqst_data.h_vendor.vendor_cmd[3]; @@ -1022,7 +1020,6 @@ unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba) unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_cmd_get_session_resp *resp; struct be_cmd_get_session_req *req; struct be_dma_mem *nonemb_cmd; struct be_mcc_wrb *wrb; @@ -1037,7 +1034,7 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) } nonemb_cmd = &phba->boot_struct.nonemb_cmd; - nonemb_cmd->size = sizeof(*resp); + nonemb_cmd->size = sizeof(struct be_cmd_get_session_resp); nonemb_cmd->va = pci_alloc_consistent(phba->ctrl.pdev, nonemb_cmd->size, &nonemb_cmd->dma); @@ -1052,7 +1049,7 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, - sizeof(*resp)); + sizeof(struct be_cmd_get_session_resp)); req->session_handle = phba->boot_struct.s_handle; sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); @@ -1297,7 +1294,7 @@ beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct beiscsi_hba *phba = iscsi_host_priv(shost); - return snprintf(buf, PAGE_SIZE, "Port Identifier : %d\n", + return snprintf(buf, PAGE_SIZE, "Port Identifier : %u\n", phba->fw_config.phys_port); } diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index f301d57320ec..308f1472f98a 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -36,66 +36,6 @@ #define PCICFG_UE_STATUS_MASK_LOW 0xA8 #define PCICFG_UE_STATUS_MASK_HI 0xAC -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_sge { - u8 pa_lo[32]; /* dword 0 */ - u8 pa_hi[32]; /* dword 1 */ - u8 length[32]; /* DWORD 2 */ -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_wrb_payload { - union { - struct amap_mcc_sge sgl[19]; - u8 embedded[59 * 32]; /* DWORDS 57 to 115 */ - } u; -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_wrb { - u8 embedded; /* DWORD 0 */ - u8 rsvd0[2]; /* DWORD 0 */ - u8 sge_count[5]; /* DWORD 0 */ - u8 rsvd1[16]; /* DWORD 0 */ - u8 special[8]; /* DWORD 0 */ - u8 payload_length[32]; - u8 tag[64]; /* DWORD 2 */ - u8 rsvd2[32]; /* DWORD 4 */ - struct amap_mcc_wrb_payload payload; -}; - -struct mcc_sge { - u32 pa_lo; /* dword 0 */ - u32 pa_hi; /* dword 1 */ - u32 length; /* DWORD 2 */ -} __packed; - -struct mcc_wrb_payload { - union { - struct mcc_sge sgl[19]; - u32 embedded[59]; /* DWORDS 57 to 115 */ - } u; -} __packed; - -#define MCC_WRB_EMBEDDED_MASK 0x00000001 - -struct mcc_wrb { - u32 dw[0]; /* DWORD 0 */ - u32 payload_length; - u32 tag[2]; /* DWORD 2 */ - u32 rsvd2[1]; /* DWORD 4 */ - struct mcc_wrb_payload payload; -}; - int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, struct beiscsi_endpoint *beiscsi_ep, From 29e80b7ce36ffcc3efd6062d87ddaf6c6f43a542 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:56:02 +0530 Subject: [PATCH 0223/1587] scsi: be2iscsi: Remove wq_name from beiscsi_hba wq_name is used only to set WQ name when its being allocated. Remove it from beiscsi_hba structure and define locally. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 9 +++++---- drivers/scsi/be2iscsi/be_main.h | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index a8e67c6186f8..a68f1beda693 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -5623,11 +5623,12 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev) static int beiscsi_dev_probe(struct pci_dev *pcidev, const struct pci_device_id *id) { - struct beiscsi_hba *phba = NULL; - struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; + struct hwi_controller *phwi_ctrlr; + struct beiscsi_hba *phba = NULL; struct be_eq_obj *pbe_eq; unsigned int s_handle; + char wq_name[20]; int ret, i; ret = beiscsi_enable_pci(pcidev); @@ -5739,9 +5740,9 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; - snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_%02x_wq", + snprintf(wq_name, sizeof(wq_name), "beiscsi_%02x_wq", phba->shost->host_no); - phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, phba->wq_name); + phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, wq_name); if (!phba->wq) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : beiscsi_dev_probe-" diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 73cc2f775291..30379de98dcb 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -410,7 +410,6 @@ struct beiscsi_hba { u8 port_name; u8 port_speed; char fw_ver_str[BEISCSI_VER_STRLEN]; - char wq_name[20]; struct workqueue_struct *wq; /* The actuak work queue */ struct be_ctrl_info ctrl; unsigned int generation; From 413f365657a8b9669bd0ba3628e9fde9ce63604e Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:56:03 +0530 Subject: [PATCH 0224/1587] scsi: be2iscsi: Add checks to validate CID alloc/free Set CID slot to 0xffff to indicate empty. Check if connection already exists in conn_table before binding. Check if endpoint already NULL before putting back CID. Break ep->conn link in free_ep to ignore completions after freeing. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_iscsi.c | 161 ++++++++++++++++--------------- drivers/scsi/be2iscsi/be_main.c | 7 +- drivers/scsi/be2iscsi/be_main.h | 1 + 3 files changed, 86 insertions(+), 83 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 0ec06256a1b8..a4844578e357 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -165,33 +165,6 @@ beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid) return cls_conn; } -/** - * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table - * @beiscsi_conn: The pointer to beiscsi_conn structure - * @phba: The phba instance - * @cid: The cid to free - */ -static int beiscsi_bindconn_cid(struct beiscsi_hba *phba, - struct beiscsi_conn *beiscsi_conn, - unsigned int cid) -{ - uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); - - if (phba->conn_table[cri_index]) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : Connection table already occupied. Detected clash\n"); - - return -EINVAL; - } else { - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : phba->conn_table[%d]=%p(beiscsi_conn)\n", - cri_index, beiscsi_conn); - - phba->conn_table[cri_index] = beiscsi_conn; - } - return 0; -} - /** * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection * @cls_session: pointer to iscsi cls session @@ -212,6 +185,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, struct hwi_wrb_context *pwrb_context; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_endpoint *ep; + uint16_t cri_index; ep = iscsi_lookup_endpoint(transport_fd); if (!ep) @@ -229,20 +203,34 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, return -EEXIST; } - - pwrb_context = &phwi_ctrlr->wrb_context[BE_GET_CRI_FROM_CID( - beiscsi_ep->ep_cid)]; + cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid); + if (phba->conn_table[cri_index]) { + if (beiscsi_conn != phba->conn_table[cri_index] || + beiscsi_ep != phba->conn_table[cri_index]->ep) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : conn_table not empty at %u: cid %u conn %p:%p\n", + cri_index, + beiscsi_ep->ep_cid, + beiscsi_conn, + phba->conn_table[cri_index]); + return -EINVAL; + } + } beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid; beiscsi_conn->ep = beiscsi_ep; beiscsi_ep->conn = beiscsi_conn; + /** + * Each connection is associated with a WRBQ kept in wrb_context. + * Store doorbell offset for transmit path. + */ + pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; beiscsi_conn->doorbell_offset = pwrb_context->doorbell_offset; - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : beiscsi_conn=%p conn=%p ep_cid=%d\n", - beiscsi_conn, conn, beiscsi_ep->ep_cid); - - return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); + "BS_%d : cid %d phba->conn_table[%u]=%p\n", + beiscsi_ep->ep_cid, cri_index, beiscsi_conn); + phba->conn_table[cri_index] = beiscsi_conn; + return 0; } static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba) @@ -973,9 +961,9 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) */ static int beiscsi_get_cid(struct beiscsi_hba *phba) { - unsigned short cid = 0xFFFF, cid_from_ulp; - struct ulp_cid_info *cid_info = NULL; uint16_t cid_avlbl_ulp0, cid_avlbl_ulp1; + unsigned short cid, cid_from_ulp; + struct ulp_cid_info *cid_info; /* Find the ULP which has more CID available */ cid_avlbl_ulp0 = (phba->cid_array_info[BEISCSI_ULP0]) ? @@ -984,20 +972,27 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba) BEISCSI_ULP1_AVLBL_CID(phba) : 0; cid_from_ulp = (cid_avlbl_ulp0 > cid_avlbl_ulp1) ? BEISCSI_ULP0 : BEISCSI_ULP1; + /** + * If iSCSI protocol is loaded only on ULP 0, and when cid_avlbl_ulp + * is ZERO for both, ULP 1 is returned. + * Check if ULP is loaded before getting new CID. + */ + if (!test_bit(cid_from_ulp, (void *)&phba->fw_config.ulp_supported)) + return BE_INVALID_CID; - if (test_bit(cid_from_ulp, (void *)&phba->fw_config.ulp_supported)) { - cid_info = phba->cid_array_info[cid_from_ulp]; - if (!cid_info->avlbl_cids) - return cid; - - cid = cid_info->cid_array[cid_info->cid_alloc++]; - - if (cid_info->cid_alloc == BEISCSI_GET_CID_COUNT( - phba, cid_from_ulp)) - cid_info->cid_alloc = 0; - - cid_info->avlbl_cids--; + cid_info = phba->cid_array_info[cid_from_ulp]; + cid = cid_info->cid_array[cid_info->cid_alloc]; + if (!cid_info->avlbl_cids || cid == BE_INVALID_CID) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : failed to get cid: available %u:%u\n", + cid_info->avlbl_cids, cid_info->cid_free); + return BE_INVALID_CID; } + /* empty the slot */ + cid_info->cid_array[cid_info->cid_alloc++] = BE_INVALID_CID; + if (cid_info->cid_alloc == BEISCSI_GET_CID_COUNT(phba, cid_from_ulp)) + cid_info->cid_alloc = 0; + cid_info->avlbl_cids--; return cid; } @@ -1008,22 +1003,28 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba) */ static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) { - uint16_t cid_post_ulp; - struct hwi_controller *phwi_ctrlr; - struct hwi_wrb_context *pwrb_context; - struct ulp_cid_info *cid_info = NULL; uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); + struct hwi_wrb_context *pwrb_context; + struct hwi_controller *phwi_ctrlr; + struct ulp_cid_info *cid_info; + uint16_t cid_post_ulp; phwi_ctrlr = phba->phwi_ctrlr; pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; cid_post_ulp = pwrb_context->ulp_num; cid_info = phba->cid_array_info[cid_post_ulp]; - cid_info->avlbl_cids++; - + /* fill only in empty slot */ + if (cid_info->cid_array[cid_info->cid_free] != BE_INVALID_CID) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : failed to put cid %u: available %u:%u\n", + cid, cid_info->avlbl_cids, cid_info->cid_free); + return; + } cid_info->cid_array[cid_info->cid_free++] = cid; if (cid_info->cid_free == BEISCSI_GET_CID_COUNT(phba, cid_post_ulp)) cid_info->cid_free = 0; + cid_info->avlbl_cids++; } /** @@ -1037,8 +1038,8 @@ static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) beiscsi_put_cid(phba, beiscsi_ep->ep_cid); beiscsi_ep->phba = NULL; - phba->ep_array[BE_GET_CRI_FROM_CID - (beiscsi_ep->ep_cid)] = NULL; + /* clear this to track freeing in beiscsi_ep_disconnect */ + phba->ep_array[BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid)] = NULL; /** * Check if any connection resource allocated by driver @@ -1049,6 +1050,11 @@ static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) return; beiscsi_conn = beiscsi_ep->conn; + /** + * Break ep->conn link here so that completions after + * this are ignored. + */ + beiscsi_ep->conn = NULL; if (beiscsi_conn->login_in_progress) { beiscsi_free_mgmt_task_handles(beiscsi_conn, beiscsi_conn->task); @@ -1079,7 +1085,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, "BS_%d : In beiscsi_open_conn\n"); beiscsi_ep->ep_cid = beiscsi_get_cid(phba); - if (beiscsi_ep->ep_cid == 0xFFFF) { + if (beiscsi_ep->ep_cid == BE_INVALID_CID) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : No free cid available\n"); return ret; @@ -1284,26 +1290,6 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) return ret; } -/** - * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table - * @phba: The phba instance - * @cid: The cid to free - */ -static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba, - unsigned int cid) -{ - uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); - - if (phba->conn_table[cri_index]) - phba->conn_table[cri_index] = NULL; - else { - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : Connection table Not occupied.\n"); - return -EINVAL; - } - return 0; -} - /** * beiscsi_ep_disconnect - Tears down the TCP connection * @ep: endpoint to be used @@ -1318,13 +1304,23 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) unsigned int tag; uint8_t mgmt_invalidate_flag, tcp_upload_flag; unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; + uint16_t cri_index; beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : In beiscsi_ep_disconnect for ep_cid = %d\n", + "BS_%d : In beiscsi_ep_disconnect for ep_cid = %u\n", beiscsi_ep->ep_cid); + cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid); + if (!phba->ep_array[cri_index]) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : ep_array at %u cid %u empty\n", + cri_index, + beiscsi_ep->ep_cid); + return; + } + if (beiscsi_ep->conn) { beiscsi_conn = beiscsi_ep->conn; iscsi_suspend_queue(beiscsi_conn->conn); @@ -1356,7 +1352,12 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) free_ep: msleep(BEISCSI_LOGOUT_SYNC_DELAY); beiscsi_free_ep(beiscsi_ep); - beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); + if (!phba->conn_table[cri_index]) + __beiscsi_log(phba, KERN_ERR, + "BS_%d : conn_table empty at %u: cid %u\n", + cri_index, + beiscsi_ep->ep_cid); + phba->conn_table[cri_index] = NULL; iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); } diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index a68f1beda693..a8a23d61fd90 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -4074,9 +4074,10 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) } /* Allocate memory for CID array */ - ptr_cid_info->cid_array = kzalloc(sizeof(void *) * - BEISCSI_GET_CID_COUNT(phba, - ulp_num), GFP_KERNEL); + ptr_cid_info->cid_array = + kcalloc(BEISCSI_GET_CID_COUNT(phba, ulp_num), + sizeof(*ptr_cid_info->cid_array), + GFP_KERNEL); if (!ptr_cid_info->cid_array) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Failed to allocate memory" diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 30379de98dcb..02a9b2d0d643 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -343,6 +343,7 @@ struct beiscsi_hba { spinlock_t async_pdu_lock; struct list_head hba_queue; #define BE_MAX_SESSION 2048 +#define BE_INVALID_CID 0xffff #define BE_SET_CID_TO_CRI(cri_index, cid) \ (phba->cid_to_cri_map[cid] = cri_index) #define BE_GET_CRI_FROM_CID(cid) (phba->cid_to_cri_map[cid]) From dd940972f36779577701f20965847e9b56b79a0e Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:56:04 +0530 Subject: [PATCH 0225/1587] scsi: be2iscsi: Reinit SGL handle, CID tables after TPE After TPE recovery, CID table needs to be repopulated as per CIDs in WRBQ creation responses. SGL handles table needs to be recreated for posting and its indices need to be resetted. This is achieved by calling beiscsi_cleanup_port when disabling and beiscsi_init_port in enabling port. Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 61 +++++++++++---------------------- 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index a8a23d61fd90..d96f706893a6 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3919,31 +3919,6 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba) kfree(phba->phwi_ctrlr); } -static int beiscsi_init_controller(struct beiscsi_hba *phba) -{ - int ret; - - ret = beiscsi_get_memory(phba); - if (ret < 0) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe -" - "Failed in beiscsi_alloc_memory\n"); - return ret; - } - - ret = hwi_init_controller(phba); - if (ret) - goto free_init; - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BM_%d : Return success from beiscsi_init_controller"); - - return 0; - -free_init: - beiscsi_free_mem(phba); - return ret; -} - static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) { struct be_mem_descriptor *mem_descr_sglh, *mem_descr_sg; @@ -4217,33 +4192,30 @@ static int beiscsi_init_port(struct beiscsi_hba *phba) { int ret; - ret = beiscsi_init_controller(phba); + ret = hwi_init_controller(phba); if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe - Failed in" - "beiscsi_init_controller\n"); + "BM_%d : init controller failed\n"); return ret; } ret = beiscsi_init_sgl_handle(phba); if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe - Failed in" - "beiscsi_init_sgl_handle\n"); - goto do_cleanup_ctrlr; + "BM_%d : init sgl handles failed\n"); + goto cleanup_port; } ret = hba_setup_cid_tbls(phba); if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Failed in hba_setup_cid_tbls\n"); + "BM_%d : setup CID table failed\n"); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); - goto do_cleanup_ctrlr; + goto cleanup_port; } - return ret; -do_cleanup_ctrlr: +cleanup_port: hwi_cleanup_port(phba); return ret; } @@ -5403,10 +5375,10 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba) phba->shost->max_id = phba->params.cxns_per_ctrl; phba->shost->can_queue = phba->params.ios_per_ctrl; - ret = hwi_init_controller(phba); - if (ret) { + ret = beiscsi_init_port(phba); + if (ret < 0) { __beiscsi_log(phba, KERN_ERR, - "BM_%d : init controller failed %d\n", ret); + "BM_%d : init port failed\n"); goto disable_msix; } @@ -5512,6 +5484,7 @@ static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload) cancel_work_sync(&pbe_eq->mcc_work); } hwi_cleanup_port(phba); + beiscsi_cleanup_port(phba); } static void beiscsi_sess_work(struct work_struct *work) @@ -5722,11 +5695,18 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, phba->shost->max_id = phba->params.cxns_per_ctrl; phba->shost->can_queue = phba->params.ios_per_ctrl; + ret = beiscsi_get_memory(phba); + if (ret < 0) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BM_%d : alloc host mem failed\n"); + goto free_port; + } + ret = beiscsi_init_port(phba); if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe-" - "Failed in beiscsi_init_port\n"); + "BM_%d : init port failed\n"); + beiscsi_free_mem(phba); goto free_port; } @@ -5868,7 +5848,6 @@ static void beiscsi_remove(struct pci_dev *pcidev) /* free all resources */ destroy_workqueue(phba->wq); - beiscsi_cleanup_port(phba); beiscsi_free_mem(phba); /* ctrl uninit */ From 5fa7db2111dfcacfd4c986a5eb4d9568386154f4 Mon Sep 17 00:00:00 2001 From: Ketan Mukadam Date: Tue, 13 Dec 2016 15:56:05 +0530 Subject: [PATCH 0226/1587] scsi: be2iscsi: Add warning message for unsupported adapter Add a warning message to indicate obsolete/unsupported BE2 Adapter Family devices Signed-off-by: Ketan Mukadam Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 2 ++ drivers/scsi/be2iscsi/be_mgmt.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index d96f706893a6..6372613e7516 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -5640,6 +5640,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, case OC_DEVICE_ID2: phba->generation = BE_GEN2; phba->iotask_fn = beiscsi_iotask; + dev_warn(&pcidev->dev, + "Obsolete/Unsupported BE2 Adapter Family\n"); break; case BE_DEVICE_ID2: case OC_DEVICE_ID3: diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 8acacd5ec796..2f6d5c2ac329 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1262,7 +1262,8 @@ beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr, case BE_DEVICE_ID1: case OC_DEVICE_ID1: case OC_DEVICE_ID2: - return snprintf(buf, PAGE_SIZE, "BE2 Adapter Family\n"); + return snprintf(buf, PAGE_SIZE, + "Obsolete/Unsupported BE2 Adapter Family\n"); break; case BE_DEVICE_ID2: case OC_DEVICE_ID3: From a5c1be7005e2992e3ae2ffa4e510e9bd4c2922e8 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 13 Dec 2016 15:56:06 +0530 Subject: [PATCH 0227/1587] scsi: be2iscsi: Update driver version Version 11.2.1.0 Signed-off-by: Jitendra Bhivare Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 02a9b2d0d643..218857926566 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -36,7 +36,7 @@ #include #define DRV_NAME "be2iscsi" -#define BUILD_STR "11.2.0.0" +#define BUILD_STR "11.2.1.0" #define BE_NAME "Emulex OneConnect" \ "Open-iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" From 703e747a6b6fa51afa6632b6963569c654062de6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 16 Dec 2016 14:10:43 +0000 Subject: [PATCH 0228/1587] scsi: qedi: return via va_end to match corresponding va_start Although on most systems va_end is a no-op, it is good practice to use va_end on the function return path, especially since the va_start documenation states: "Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function." Found with static analysis by CoverityScan, CIDs 1389477-1389479 Signed-off-by: Colin Ian King Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_dbg.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qedi/qedi_dbg.c b/drivers/scsi/qedi/qedi_dbg.c index 2bdedb9c39bc..8fd28b056f73 100644 --- a/drivers/scsi/qedi/qedi_dbg.c +++ b/drivers/scsi/qedi/qedi_dbg.c @@ -52,7 +52,7 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line, vaf.va = &va; if (!(qedi_dbg_log & QEDI_LOG_WARN)) - return; + goto ret; if (likely(qedi) && likely(qedi->pdev)) pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), @@ -60,6 +60,7 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line, else pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); +ret: va_end(va); } @@ -80,7 +81,7 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, vaf.va = &va; if (!(qedi_dbg_log & QEDI_LOG_NOTICE)) - return; + goto ret; if (likely(qedi) && likely(qedi->pdev)) pr_notice("[%s]:[%s:%d]:%d: %pV", @@ -89,6 +90,7 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, else pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); +ret: va_end(va); } @@ -109,7 +111,7 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, vaf.va = &va; if (!(qedi_dbg_log & level)) - return; + goto ret; if (likely(qedi) && likely(qedi->pdev)) pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), @@ -117,6 +119,7 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, else pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); +ret: va_end(va); } From 364757e4682c0a046dc7da20d359a9a37dfff703 Mon Sep 17 00:00:00 2001 From: Cao jin Date: Mon, 19 Dec 2016 14:20:29 +0800 Subject: [PATCH 0229/1587] scsi: qla4xxx: comments correction Signed-off-by: Cao jin Acked-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 9fbb33fc90c7..ac52150d1569 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -9539,15 +9539,15 @@ exit_host_reset: * driver calls the following device driver's callbacks * * - Fatal Errors - link_reset - * - Non-Fatal Errors - driver's pci_error_detected() which + * - Non-Fatal Errors - driver's error_detected() which * returns CAN_RECOVER, NEED_RESET or DISCONNECT. * * PCI AER driver calls - * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled + * CAN_RECOVER - driver's mmio_enabled(), mmio_enabled() * returns RECOVERED or NEED_RESET if fw_hung * NEED_RESET - driver's slot_reset() * DISCONNECT - device is dead & cannot recover - * RECOVERED - driver's pci_resume() + * RECOVERED - driver's resume() */ static pci_ers_result_t qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) From ad4d05329df5e9825cac3132e12453a6c12915b8 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 2 Jan 2017 14:30:31 +0100 Subject: [PATCH 0230/1587] udf: Make stat on symlink report symlink length as st_size UDF encodes symlinks in a more complex fashion and thus i_size of a symlink does not match the lenght of a string returned by readlink(2). This confuses some applications (see bug 191241) and may be considered a violation of POSIX. Fix the problem by reading the link into page cache in response to stat(2) call and report the length of the decoded path. Signed-off-by: Jan Kara --- fs/udf/inode.c | 2 +- fs/udf/namei.c | 2 +- fs/udf/symlink.c | 30 ++++++++++++++++++++++++++++++ fs/udf/udfdecl.h | 1 + 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 3a5ac2221a88..5f643c93f564 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1547,7 +1547,7 @@ reread: break; case ICBTAG_FILE_TYPE_SYMLINK: inode->i_data.a_ops = &udf_symlink_aops; - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &udf_symlink_inode_operations; inode_nohighmem(inode); inode->i_mode = S_IFLNK | S_IRWXUGO; break; diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 2d65e280748b..babf48d0e553 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -931,7 +931,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, } inode->i_data.a_ops = &udf_symlink_aops; - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &udf_symlink_inode_operations; inode_nohighmem(inode); if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 8d619773056b..f7dfef53f739 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -152,9 +152,39 @@ out_unmap: return err; } +static int udf_symlink_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct inode *inode = d_backing_inode(dentry); + struct page *page; + + generic_fillattr(inode, stat); + page = read_mapping_page(inode->i_mapping, 0, NULL); + if (IS_ERR(page)) + return PTR_ERR(page); + /* + * UDF uses non-trivial encoding of symlinks so i_size does not match + * number of characters reported by readlink(2) which apparently some + * applications expect. Also POSIX says that "The value returned in the + * st_size field shall be the length of the contents of the symbolic + * link, and shall not count a trailing null if one is present." So + * let's report the length of string returned by readlink(2) for + * st_size. + */ + stat->size = strlen(page_address(page)); + put_page(page); + + return 0; +} + /* * symlinks can't do much... */ const struct address_space_operations udf_symlink_aops = { .readpage = udf_symlink_filler, }; + +const struct inode_operations udf_symlink_inode_operations = { + .get_link = page_get_link, + .getattr = udf_symlink_getattr, +}; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index b608624e7089..63b034984378 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -84,6 +84,7 @@ extern const struct inode_operations udf_dir_inode_operations; extern const struct file_operations udf_dir_operations; extern const struct inode_operations udf_file_inode_operations; extern const struct file_operations udf_file_operations; +extern const struct inode_operations udf_symlink_inode_operations; extern const struct address_space_operations udf_aops; extern const struct address_space_operations udf_adinicb_aops; extern const struct address_space_operations udf_symlink_aops; From 3429fb3cda34f28ca2942ccc4fa7a7865b3ed978 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 5 Jan 2017 15:52:55 +0000 Subject: [PATCH 0231/1587] pinctrl: Fix panic when pinctrl devices with hogs are unregistered Commit df61b366af26 ('pinctrl: core: Use delayed work for hogs') deferred part of the registration for pinctrl devices if the pinctrl device has hogs. This introduced a window where if the pinctrl device with hogs was sucessfully registered, but then unregistered again (which could be caused by parent device being probe deferred) before the delayed work has chanced to run, then this will cause a kernel panic to occur because: 1. The 'pctldev->p' has not yet been initialised and when unregistering the pinctrl device we only check to see if it is an error value, but now it could also be NULL. 2. The pinctrl device may not have been added to the 'pinctrldev_list' list and we don't check to see if it was added before removing. Fix up the above by checking to see if the 'pctldev->p' pointer is an error value or NULL before putting the pinctrl device and verifying that the pinctrl device is present in 'pinctrldev_list' before removing. Fixes: df61b366af26 ('pinctrl: core: Use delayed work for hogs') Signed-off-by: Jon Hunter Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index d311d73852a0..9f305ac06275 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -2064,6 +2064,8 @@ EXPORT_SYMBOL_GPL(pinctrl_register); void pinctrl_unregister(struct pinctrl_dev *pctldev) { struct pinctrl_gpio_range *range, *n; + struct pinctrl_dev *p, *p1; + if (pctldev == NULL) return; @@ -2072,13 +2074,15 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) pinctrl_remove_device_debugfs(pctldev); mutex_unlock(&pctldev->mutex); - if (!IS_ERR(pctldev->p)) + if (!IS_ERR_OR_NULL(pctldev->p)) pinctrl_put(pctldev->p); mutex_lock(&pinctrldev_list_mutex); mutex_lock(&pctldev->mutex); /* TODO: check that no pinmuxes are still active? */ - list_del(&pctldev->node); + list_for_each_entry_safe(p, p1, &pinctrldev_list, node) + if (p == pctldev) + list_del(&p->node); pinmux_generic_free_functions(pctldev); pinctrl_generic_free_groups(pctldev); /* Destroy descriptor tree */ From 2fcf5cc3be06126f9aa2430ca6d739c8b3c5aaf5 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Fri, 16 Dec 2016 08:01:28 -0600 Subject: [PATCH 0232/1587] GFS2: Limit number of transaction blocks requested for truncates This patch limits the number of transaction blocks requested during file truncates. If we have very large multi-terabyte files, and want to delete or truncate them, they might span so many resource groups that we overflow the journal blocks, and cause an assert failure. By limiting the number of blocks in the transaction, we prevent this overflow and give other running processes time to do transactions. The limiting factor I chose is sd_log_thresh2 which is currently set to 4/5ths of the journal. This same ratio is used in function gfs2_ail_flush_reqd to determine when a log flush is required. If we make the maximum value less than this, we can get into a infinite hang whereby the log stops moving because the number of used blocks is less than the threshold and the iterative loop needs more, but since we're under the threshold, the log daemon never starts any IO on the log. Signed-off-by: Bob Peterson --- fs/gfs2/bmap.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 645721f3ff00..cbad0ef6806f 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -720,6 +720,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrp_list rlist; + struct gfs2_trans *tr; u64 bn, bstart; u32 blen, btotal; __be64 *p; @@ -728,6 +729,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, unsigned int revokes = 0; int x; int error; + int jblocks_rqsted; error = gfs2_rindex_update(sdp); if (error) @@ -791,12 +793,17 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, if (gfs2_rs_active(&ip->i_res)) /* needs to be done with the rgrp glock held */ gfs2_rs_deltree(&ip->i_res); - error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + - RES_INDIRECT + RES_STATFS + RES_QUOTA, - revokes); +restart: + jblocks_rqsted = rg_blocks + RES_DINODE + + RES_INDIRECT + RES_STATFS + RES_QUOTA + + gfs2_struct2blk(sdp, revokes, sizeof(u64)); + if (jblocks_rqsted > atomic_read(&sdp->sd_log_thresh2)) + jblocks_rqsted = atomic_read(&sdp->sd_log_thresh2); + error = gfs2_trans_begin(sdp, jblocks_rqsted, revokes); if (error) goto out_rg_gunlock; + tr = current->journal_info; down_write(&ip->i_rw_mutex); gfs2_trans_add_meta(ip->i_gl, dibh); @@ -810,6 +817,16 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, if (!*p) continue; + /* check for max reasonable journal transaction blocks */ + if (tr->tr_num_buf_new + RES_STATFS + + RES_QUOTA >= atomic_read(&sdp->sd_log_thresh2)) { + if (rg_blocks >= tr->tr_num_buf_new) + rg_blocks -= tr->tr_num_buf_new; + else + rg_blocks = 0; + break; + } + bn = be64_to_cpu(*p); if (bstart + blen == bn) @@ -827,6 +844,9 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, *p = 0; gfs2_add_inode_blocks(&ip->i_inode, -1); } + if (p == bottom) + rg_blocks = 0; + if (bstart) { __gfs2_free_blocks(ip, bstart, blen, metadata); btotal += blen; @@ -844,6 +864,9 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, gfs2_trans_end(sdp); + if (rg_blocks) + goto restart; + out_rg_gunlock: gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); out_rlist: From f07b352021483a3a38f081dc284928400a9c1d2c Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 5 Jan 2017 16:01:45 -0500 Subject: [PATCH 0233/1587] GFS2: Made logd daemon take into account log demand Before this patch, the logd daemon only tried to flush things when the log blocks pinned exceeded a certain threshold. But when we're deleting very large files, it may require a huge number of journal blocks, and that, in turn, may exceed the threshold. This patch factors that into account. Signed-off-by: Bob Peterson --- fs/gfs2/incore.h | 1 + fs/gfs2/log.c | 9 +++++++-- fs/gfs2/ops_fstype.c | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index a6a3389a07fc..00d8dc20ea3a 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -794,6 +794,7 @@ struct gfs2_sbd { atomic_t sd_log_thresh1; atomic_t sd_log_thresh2; atomic_t sd_log_blks_free; + atomic_t sd_log_blks_needed; wait_queue_head_t sd_log_waitq; wait_queue_head_t sd_logd_waitq; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index e58ccef09c91..4df349c7f022 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -349,6 +349,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) if (gfs2_assert_warn(sdp, blks) || gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks)) return -EINVAL; + atomic_add(blks, &sdp->sd_log_blks_needed); retry: free_blocks = atomic_read(&sdp->sd_log_blks_free); if (unlikely(free_blocks <= wanted)) { @@ -370,6 +371,7 @@ retry: wake_up(&sdp->sd_reserving_log_wait); goto retry; } + atomic_sub(blks, &sdp->sd_log_blks_needed); trace_gfs2_log_blocks(sdp, -blks); /* @@ -891,13 +893,16 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp) { - return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1)); + return (atomic_read(&sdp->sd_log_pinned) + + atomic_read(&sdp->sd_log_blks_needed) >= + atomic_read(&sdp->sd_log_thresh1)); } static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp) { unsigned int used_blocks = sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free); - return used_blocks >= atomic_read(&sdp->sd_log_thresh2); + return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >= + atomic_read(&sdp->sd_log_thresh2); } /** diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index ff72ac6439c8..86281a918c7a 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -683,6 +683,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) goto fail_jindex; } + atomic_set(&sdp->sd_log_blks_needed, 0); if (sdp->sd_args.ar_spectator) { sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0); atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks); From e64b8cc72bf9958efd4f38e55d2980c95e0ce679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 6 Dec 2016 09:32:03 +0100 Subject: [PATCH 0234/1587] DT: leds: Improve examples by adding some context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During my work on some new LED trigger I tried adding example similar to the existing ones which received following comment from Rob: > It's not really clear in the example this is an LED node as it is > incomplete. Keeping that in mind I suggest adding context for the existing example entries in hope to make documentation more clear. Signed-off-by: Rafał Miłecki Signed-off-by: Jacek Anaszewski --- .../devicetree/bindings/leds/common.txt | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt index 696be5792625..24b656014089 100644 --- a/Documentation/devicetree/bindings/leds/common.txt +++ b/Documentation/devicetree/bindings/leds/common.txt @@ -61,16 +61,24 @@ property can be omitted. Examples: -system-status { - label = "Status"; - linux,default-trigger = "heartbeat"; - ... +gpio-leds { + compatible = "gpio-leds"; + + system-status { + label = "Status"; + linux,default-trigger = "heartbeat"; + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + }; }; -camera-flash { - label = "Flash"; - led-sources = <0>, <1>; - led-max-microamp = <50000>; - flash-max-microamp = <320000>; - flash-max-timeout-us = <500000>; +max77693-led { + compatible = "maxim,max77693-led"; + + camera-flash { + label = "Flash"; + led-sources = <0>, <1>; + led-max-microamp = <50000>; + flash-max-microamp = <320000>; + flash-max-timeout-us = <500000>; + }; }; From 4e552c8cb5bc9137e67e035bab8df6dddbca7384 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Thu, 5 Jan 2017 11:34:12 +0900 Subject: [PATCH 0235/1587] leds: add LED_ON brightness as boolean value Some devices do not handle the led brightness or simply don't care about it. Conceptually said devices want to just switch on or off the led. It is useless in this case to have a 255 range of brightness, while just having an LED_ON and LED_OFF improves the boolean meaning of the led status. Signed-off-by: Andi Shyti Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- include/linux/leds.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/leds.h b/include/linux/leds.h index 569cb531094c..bb50d0151e75 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -27,6 +27,7 @@ struct device; enum led_brightness { LED_OFF = 0, + LED_ON = 1, LED_HALF = 127, LED_FULL = 255, }; From 66cc820f9cbf12f1c6c84fb7392847b7fa5e76c4 Mon Sep 17 00:00:00 2001 From: Dolev Raviv Date: Thu, 22 Dec 2016 18:39:42 -0800 Subject: [PATCH 0236/1587] scsi: ufs: dump debug info during failures Inserts driver dumps for UFS Host Controller registers, Transfer Requests and Task Management Requests. The dumps will occur on driver initialization failure, ufshcd_abort() and on error handling path. Signed-off-by: Dolev Raviv Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 129 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshci.h | 3 + 2 files changed, 132 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 20e5e5fb048c..6e2e0cd86ce3 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -94,6 +94,9 @@ _ret; \ }) +#define ufshcd_hex_dump(prefix_str, buf, len) \ +print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 4, buf, len, false) + static u32 ufs_query_desc_max_size[] = { QUERY_DESC_DEVICE_MAX_SIZE, QUERY_DESC_CONFIGURAION_MAX_SIZE, @@ -267,6 +270,77 @@ static inline void ufshcd_remove_non_printable(char *val) *val = ' '; } +static void ufshcd_print_host_regs(struct ufs_hba *hba) +{ + /* + * hex_dump reads its data without the readl macro. This might + * cause inconsistency issues on some platform, as the printed + * values may be from cache and not the most recent value. + * To know whether you are looking at an un-cached version verify + * that IORESOURCE_MEM flag is on when xxx_get_resource() is invoked + * during platform/pci probe function. + */ + ufshcd_hex_dump("host regs: ", hba->mmio_base, UFSHCI_REG_SPACE_SIZE); + dev_err(hba->dev, "hba->ufs_version = 0x%x, hba->capabilities = 0x%x\n", + hba->ufs_version, hba->capabilities); + dev_err(hba->dev, + "hba->outstanding_reqs = 0x%x, hba->outstanding_tasks = 0x%x\n", + (u32)hba->outstanding_reqs, (u32)hba->outstanding_tasks); +} + +static +void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) +{ + struct ufshcd_lrb *lrbp; + int tag; + + for_each_set_bit(tag, &bitmap, hba->nutrs) { + lrbp = &hba->lrb[tag]; + + dev_err(hba->dev, "UPIU[%d] - Transfer Request Descriptor\n", + tag); + ufshcd_hex_dump("UPIU TRD: ", lrbp->utr_descriptor_ptr, + sizeof(struct utp_transfer_req_desc)); + dev_err(hba->dev, "UPIU[%d] - Request UPIU\n", tag); + ufshcd_hex_dump("UPIU REQ: ", lrbp->ucd_req_ptr, + sizeof(struct utp_upiu_req)); + dev_err(hba->dev, "UPIU[%d] - Response UPIU\n", tag); + ufshcd_hex_dump("UPIU RSP: ", lrbp->ucd_rsp_ptr, + sizeof(struct utp_upiu_rsp)); + if (pr_prdt) { + int prdt_length = le16_to_cpu( + lrbp->utr_descriptor_ptr->prd_table_length); + + dev_err(hba->dev, "UPIU[%d] - PRDT - %d entries\n", tag, + prdt_length); + ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr, + sizeof(struct ufshcd_sg_entry) * + prdt_length); + } + } +} + +static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap) +{ + struct utp_task_req_desc *tmrdp; + int tag; + + for_each_set_bit(tag, &bitmap, hba->nutmrs) { + tmrdp = &hba->utmrdl_base_addr[tag]; + dev_err(hba->dev, "TM[%d] - Task Management Header\n", tag); + ufshcd_hex_dump("TM TRD: ", &tmrdp->header, + sizeof(struct request_desc_header)); + dev_err(hba->dev, "TM[%d] - Task Management Request UPIU\n", + tag); + ufshcd_hex_dump("TM REQ: ", tmrdp->task_req_upiu, + sizeof(struct utp_upiu_req)); + dev_err(hba->dev, "TM[%d] - Task Management Response UPIU\n", + tag); + ufshcd_hex_dump("TM RSP: ", tmrdp->task_rsp_upiu, + sizeof(struct utp_task_req_desc)); + } +} + /* * ufshcd_wait_for_register - wait for register value to change * @hba - per-adapter interface @@ -2391,6 +2465,32 @@ out: return -ENOMEM; } +/** + * ufshcd_print_pwr_info - print power params as saved in hba + * power info + * @hba: per-adapter instance + */ +static void ufshcd_print_pwr_info(struct ufs_hba *hba) +{ + static const char * const names[] = { + "INVALID MODE", + "FAST MODE", + "SLOW_MODE", + "INVALID MODE", + "FASTAUTO_MODE", + "SLOWAUTO_MODE", + "INVALID MODE", + }; + + dev_info(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", + __func__, + hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, + hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, + names[hba->pwr_info.pwr_rx], + names[hba->pwr_info.pwr_tx], + hba->pwr_info.hs_rate); +} + /** * ufshcd_host_memory_configure - configure local reference block with * memory offsets @@ -2973,6 +3073,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, sizeof(struct ufs_pa_layer_attr)); } + ufshcd_print_pwr_info(hba); + return ret; } @@ -3656,6 +3758,8 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) break; } /* end of switch */ + if (host_byte(result) != DID_OK) + ufshcd_print_trs(hba, 1 << lrbp->task_tag, true); return result; } @@ -4327,6 +4431,22 @@ static void ufshcd_check_errors(struct ufs_hba *hba) scsi_block_requests(hba->host); hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED; + + /* dump controller state before resetting */ + if (hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) { + bool pr_prdt = !!(hba->saved_err & + SYSTEM_BUS_FATAL_ERROR); + + dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x\n", + __func__, hba->saved_err, + hba->saved_uic_err); + + ufshcd_print_host_regs(hba); + ufshcd_print_pwr_info(hba); + ufshcd_print_tmrs(hba, hba->outstanding_tasks); + ufshcd_print_trs(hba, hba->outstanding_reqs, + pr_prdt); + } schedule_work(&hba->eh_work); } } @@ -4617,6 +4737,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) __func__, tag); } + /* Print Transfer Request of aborted task */ + dev_err(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag); + scsi_print_command(hba->lrb[tag].cmd); + ufshcd_print_host_regs(hba); + ufshcd_print_pwr_info(hba); + ufshcd_print_trs(hba, 1 << tag, true); + lrbp = &hba->lrb[tag]; for (poll_cnt = 100; poll_cnt; poll_cnt--) { err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, @@ -5256,6 +5383,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) goto out; ufshcd_init_pwr_info(hba); + ufshcd_print_pwr_info(hba); /* set the default level for urgent bkops */ hba->urgent_bkops_lvl = BKOPS_STATUS_PERF_IMPACT; @@ -6795,6 +6923,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) err = ufshcd_hba_enable(hba); if (err) { dev_err(hba->dev, "Host controller enable failed\n"); + ufshcd_print_host_regs(hba); goto out_remove_scsi_host; } diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 8c5190e2e1c9..d14e9b965d1e 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -72,6 +72,9 @@ enum { REG_UIC_COMMAND_ARG_1 = 0x94, REG_UIC_COMMAND_ARG_2 = 0x98, REG_UIC_COMMAND_ARG_3 = 0x9C, + + UFSHCI_REG_SPACE_SIZE = 0xA0, + REG_UFS_CCAP = 0x100, REG_UFS_CRYPTOCAP = 0x104, From 7ff5ab4736333431311a4cbbfb574b155758b08c Mon Sep 17 00:00:00 2001 From: "subhashj@codeaurora.org" Date: Thu, 22 Dec 2016 18:39:51 -0800 Subject: [PATCH 0237/1587] scsi: ufs: add tracing support This change adds the ftrace support for following: 1. UFS initialization time 2. Clock gating states 3. Clock scaling states 4. Power management APIs latency 5. BKOPs enable/disable Usage: echo 1 > /sys/kernel/debug/tracing/events/ufs/enable cat /sys/kernel/debug/tracing/trace_pipe Reviewed-by: Sahitya Tummala Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 85 ++++++++++++++--- include/trace/events/ufs.h | 185 +++++++++++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+), 12 deletions(-) create mode 100644 include/trace/events/ufs.h diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 6e2e0cd86ce3..0b8c380392b9 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -45,6 +45,9 @@ #include "ufs_quirks.h" #include "unipro.h" +#define CREATE_TRACE_POINTS +#include + #define UFSHCD_REQ_SENSE_SIZE 18 #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ @@ -801,6 +804,8 @@ start: case REQ_CLKS_OFF: if (cancel_delayed_work(&hba->clk_gating.gate_work)) { hba->clk_gating.state = CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); break; } /* @@ -811,6 +816,8 @@ start: case CLKS_OFF: scsi_block_requests(hba->host); hba->clk_gating.state = REQ_CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); schedule_work(&hba->clk_gating.ungate_work); /* * fall through to check if we should wait for this @@ -855,6 +862,8 @@ static void ufshcd_gate_work(struct work_struct *work) if (hba->clk_gating.is_suspended || (hba->clk_gating.state == REQ_CLKS_ON)) { hba->clk_gating.state = CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); goto rel_lock; } @@ -870,6 +879,8 @@ static void ufshcd_gate_work(struct work_struct *work) if (ufshcd_can_hibern8_during_gating(hba)) { if (ufshcd_uic_hibern8_enter(hba)) { hba->clk_gating.state = CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); goto out; } ufshcd_set_link_hibern8(hba); @@ -893,9 +904,11 @@ static void ufshcd_gate_work(struct work_struct *work) * new requests arriving before the current cancel work is done. */ spin_lock_irqsave(hba->host->host_lock, flags); - if (hba->clk_gating.state == REQ_CLKS_OFF) + if (hba->clk_gating.state == REQ_CLKS_OFF) { hba->clk_gating.state = CLKS_OFF; - + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); + } rel_lock: spin_unlock_irqrestore(hba->host->host_lock, flags); out: @@ -918,6 +931,7 @@ static void __ufshcd_release(struct ufs_hba *hba) return; hba->clk_gating.state = REQ_CLKS_OFF; + trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); schedule_delayed_work(&hba->clk_gating.gate_work, msecs_to_jiffies(hba->clk_gating.delay_ms)); } @@ -3932,6 +3946,7 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba) } hba->auto_bkops_enabled = true; + trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Enabled"); /* No need of URGENT_BKOPS exception from the device */ err = ufshcd_disable_ee(hba, MASK_EE_URGENT_BKOPS); @@ -3982,6 +3997,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba) } hba->auto_bkops_enabled = false; + trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Disabled"); out: return err; } @@ -5377,6 +5393,7 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) static int ufshcd_probe_hba(struct ufs_hba *hba) { int ret; + ktime_t start = ktime_get(); ret = ufshcd_link_startup(hba); if (ret) @@ -5468,6 +5485,9 @@ out: ufshcd_hba_exit(hba); } + trace_ufshcd_init(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->uic_link_state, hba->curr_dev_pwr_mode); return ret; } @@ -5817,11 +5837,14 @@ out: if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled) clk_disable_unprepare(clki->clk); } - } else if (on) { + } else if (!ret && on) { spin_lock_irqsave(hba->host->host_lock, flags); hba->clk_gating.state = CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); spin_unlock_irqrestore(hba->host->host_lock, flags); } + return ret; } @@ -6304,6 +6327,7 @@ disable_clks: __ufshcd_setup_clocks(hba, false, true); hba->clk_gating.state = CLKS_OFF; + trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); /* * Disable the host irq as host controller as there won't be any * host controller transaction expected till resume. @@ -6436,6 +6460,7 @@ out: int ufshcd_system_suspend(struct ufs_hba *hba) { int ret = 0; + ktime_t start = ktime_get(); if (!hba || !hba->is_powered) return 0; @@ -6462,6 +6487,9 @@ int ufshcd_system_suspend(struct ufs_hba *hba) ret = ufshcd_suspend(hba, UFS_SYSTEM_PM); out: + trace_ufshcd_system_suspend(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->uic_link_state, hba->curr_dev_pwr_mode); if (!ret) hba->is_sys_suspended = true; return ret; @@ -6477,6 +6505,9 @@ EXPORT_SYMBOL(ufshcd_system_suspend); int ufshcd_system_resume(struct ufs_hba *hba) { + int ret = 0; + ktime_t start = ktime_get(); + if (!hba) return -EINVAL; @@ -6485,9 +6516,14 @@ int ufshcd_system_resume(struct ufs_hba *hba) * Let the runtime resume take care of resuming * if runtime suspended. */ - return 0; - - return ufshcd_resume(hba, UFS_SYSTEM_PM); + goto out; + else + ret = ufshcd_resume(hba, UFS_SYSTEM_PM); +out: + trace_ufshcd_system_resume(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->uic_link_state, hba->curr_dev_pwr_mode); + return ret; } EXPORT_SYMBOL(ufshcd_system_resume); @@ -6501,13 +6537,21 @@ EXPORT_SYMBOL(ufshcd_system_resume); */ int ufshcd_runtime_suspend(struct ufs_hba *hba) { + int ret = 0; + ktime_t start = ktime_get(); + if (!hba) return -EINVAL; if (!hba->is_powered) - return 0; - - return ufshcd_suspend(hba, UFS_RUNTIME_PM); + goto out; + else + ret = ufshcd_suspend(hba, UFS_RUNTIME_PM); +out: + trace_ufshcd_runtime_suspend(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->uic_link_state, hba->curr_dev_pwr_mode); + return ret; } EXPORT_SYMBOL(ufshcd_runtime_suspend); @@ -6534,13 +6578,21 @@ EXPORT_SYMBOL(ufshcd_runtime_suspend); */ int ufshcd_runtime_resume(struct ufs_hba *hba) { + int ret = 0; + ktime_t start = ktime_get(); + if (!hba) return -EINVAL; if (!hba->is_powered) - return 0; - - return ufshcd_resume(hba, UFS_RUNTIME_PM); + goto out; + else + ret = ufshcd_resume(hba, UFS_RUNTIME_PM); +out: + trace_ufshcd_runtime_resume(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->uic_link_state, hba->curr_dev_pwr_mode); + return ret; } EXPORT_SYMBOL(ufshcd_runtime_resume); @@ -6684,6 +6736,11 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) clki->max_freq, ret); break; } + trace_ufshcd_clk_scaling(dev_name(hba->dev), + "scaled up", clki->name, + clki->curr_freq, + clki->max_freq); + clki->curr_freq = clki->max_freq; } else if (!scale_up && clki->min_freq) { @@ -6696,6 +6753,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) clki->min_freq, ret); break; } + trace_ufshcd_clk_scaling(dev_name(hba->dev), + "scaled down", clki->name, + clki->curr_freq, + clki->min_freq); clki->curr_freq = clki->min_freq; } } diff --git a/include/trace/events/ufs.h b/include/trace/events/ufs.h new file mode 100644 index 000000000000..57743b6ed0b0 --- /dev/null +++ b/include/trace/events/ufs.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ufs + +#if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_UFS_H + +#include + +#define UFS_LINK_STATES \ + EM(UIC_LINK_OFF_STATE) \ + EM(UIC_LINK_ACTIVE_STATE) \ + EMe(UIC_LINK_HIBERN8_STATE) + +#define UFS_PWR_MODES \ + EM(UFS_ACTIVE_PWR_MODE) \ + EM(UFS_SLEEP_PWR_MODE) \ + EMe(UFS_POWERDOWN_PWR_MODE) + +#define UFSCHD_CLK_GATING_STATES \ + EM(CLKS_OFF) \ + EM(CLKS_ON) \ + EM(REQ_CLKS_OFF) \ + EMe(REQ_CLKS_ON) + +/* Enums require being exported to userspace, for user tool parsing */ +#undef EM +#undef EMe +#define EM(a) TRACE_DEFINE_ENUM(a); +#define EMe(a) TRACE_DEFINE_ENUM(a); + +UFS_LINK_STATES; +UFS_PWR_MODES; +UFSCHD_CLK_GATING_STATES; + +/* + * Now redefine the EM() and EMe() macros to map the enums to the strings + * that will be printed in the output. + */ +#undef EM +#undef EMe +#define EM(a) { a, #a }, +#define EMe(a) { a, #a } + +TRACE_EVENT(ufshcd_clk_gating, + + TP_PROTO(const char *dev_name, int state), + + TP_ARGS(dev_name, state), + + TP_STRUCT__entry( + __string(dev_name, dev_name) + __field(int, state) + ), + + TP_fast_assign( + __assign_str(dev_name, dev_name); + __entry->state = state; + ), + + TP_printk("%s: gating state changed to %s", + __get_str(dev_name), + __print_symbolic(__entry->state, UFSCHD_CLK_GATING_STATES)) +); + +TRACE_EVENT(ufshcd_clk_scaling, + + TP_PROTO(const char *dev_name, const char *state, const char *clk, + u32 prev_state, u32 curr_state), + + TP_ARGS(dev_name, state, clk, prev_state, curr_state), + + TP_STRUCT__entry( + __string(dev_name, dev_name) + __string(state, state) + __string(clk, clk) + __field(u32, prev_state) + __field(u32, curr_state) + ), + + TP_fast_assign( + __assign_str(dev_name, dev_name); + __assign_str(state, state); + __assign_str(clk, clk); + __entry->prev_state = prev_state; + __entry->curr_state = curr_state; + ), + + TP_printk("%s: %s %s from %u to %u Hz", + __get_str(dev_name), __get_str(state), __get_str(clk), + __entry->prev_state, __entry->curr_state) +); + +TRACE_EVENT(ufshcd_auto_bkops_state, + + TP_PROTO(const char *dev_name, const char *state), + + TP_ARGS(dev_name, state), + + TP_STRUCT__entry( + __string(dev_name, dev_name) + __string(state, state) + ), + + TP_fast_assign( + __assign_str(dev_name, dev_name); + __assign_str(state, state); + ), + + TP_printk("%s: auto bkops - %s", + __get_str(dev_name), __get_str(state)) +); + +DECLARE_EVENT_CLASS(ufshcd_template, + TP_PROTO(const char *dev_name, int err, s64 usecs, + int dev_state, int link_state), + + TP_ARGS(dev_name, err, usecs, dev_state, link_state), + + TP_STRUCT__entry( + __field(s64, usecs) + __field(int, err) + __string(dev_name, dev_name) + __field(int, dev_state) + __field(int, link_state) + ), + + TP_fast_assign( + __entry->usecs = usecs; + __entry->err = err; + __assign_str(dev_name, dev_name); + __entry->dev_state = dev_state; + __entry->link_state = link_state; + ), + + TP_printk( + "%s: took %lld usecs, dev_state: %s, link_state: %s, err %d", + __get_str(dev_name), + __entry->usecs, + __print_symbolic(__entry->dev_state, UFS_PWR_MODES), + __print_symbolic(__entry->link_state, UFS_LINK_STATES), + __entry->err + ) +); + +DEFINE_EVENT(ufshcd_template, ufshcd_system_suspend, + TP_PROTO(const char *dev_name, int err, s64 usecs, + int dev_state, int link_state), + TP_ARGS(dev_name, err, usecs, dev_state, link_state)); + +DEFINE_EVENT(ufshcd_template, ufshcd_system_resume, + TP_PROTO(const char *dev_name, int err, s64 usecs, + int dev_state, int link_state), + TP_ARGS(dev_name, err, usecs, dev_state, link_state)); + +DEFINE_EVENT(ufshcd_template, ufshcd_runtime_suspend, + TP_PROTO(const char *dev_name, int err, s64 usecs, + int dev_state, int link_state), + TP_ARGS(dev_name, err, usecs, dev_state, link_state)); + +DEFINE_EVENT(ufshcd_template, ufshcd_runtime_resume, + TP_PROTO(const char *dev_name, int err, s64 usecs, + int dev_state, int link_state), + TP_ARGS(dev_name, err, usecs, dev_state, link_state)); + +DEFINE_EVENT(ufshcd_template, ufshcd_init, + TP_PROTO(const char *dev_name, int err, s64 usecs, + int dev_state, int link_state), + TP_ARGS(dev_name, err, usecs, dev_state, link_state)); +#endif /* if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ) */ + +/* This part must be outside protection */ +#include From e7d38257a40f880c6625fac33956d5e99dcd63a6 Mon Sep 17 00:00:00 2001 From: Dolev Raviv Date: Thu, 22 Dec 2016 18:40:07 -0800 Subject: [PATCH 0238/1587] scsi: ufs: fix multiple ufs spec violation When a command to a W-LU is timed out via scsi, error handling will treat it as any other LU and send commands such as START_STOP with wrong format or task abort. Those commands are illegal for W-LU according to the UFS spec. To solve it, when an error is recognized those steps are skipped and the last step, reset and restore process, is initiated. Signed-off-by: Dolev Raviv Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0b8c380392b9..a6a4a4302ca9 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -218,6 +218,7 @@ static struct ufs_dev_fix ufs_fixups[] = { static void ufshcd_tmc_handler(struct ufs_hba *hba); static void ufshcd_async_scan(void *data, async_cookie_t cookie); static int ufshcd_reset_and_restore(struct ufs_hba *hba); +static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); static void ufshcd_hba_exit(struct ufs_hba *hba); static int ufshcd_probe_hba(struct ufs_hba *hba); @@ -4730,6 +4731,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) host = cmd->device->host; hba = shost_priv(host); tag = cmd->request->tag; + lrbp = &hba->lrb[tag]; if (!ufshcd_valid_tag(hba, tag)) { dev_err(hba->dev, "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p", @@ -4737,6 +4739,16 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) BUG(); } + /* + * Task abort to the device W-LUN is illegal. When this command + * will fail, due to spec violation, scsi err handling next step + * will be to send LU reset which, again, is a spec violation. + * To avoid these unnecessary/illegal step we skip to the last error + * handling stage: reset and restore. + */ + if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN) + return ufshcd_eh_host_reset_handler(cmd); + ufshcd_hold(hba, false); reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); /* If command is already aborted/completed, return SUCCESS */ @@ -4760,7 +4772,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) ufshcd_print_pwr_info(hba); ufshcd_print_trs(hba, 1 << tag, true); - lrbp = &hba->lrb[tag]; for (poll_cnt = 100; poll_cnt; poll_cnt--) { err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, UFS_QUERY_TASK, &resp); From b427411abb3d61c234cb7dd58bc9b9f92c0fd8cb Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Thu, 22 Dec 2016 18:40:39 -0800 Subject: [PATCH 0239/1587] scsi: ufs: Add sysfs node to dynamically control clock gating Provide an option to enable/disable clock gating during runtime. Write 1 or 0 to "clkgate_enable" sysfs node to enable/disable clock gating. Signed-off-by: Sahitya Tummala Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 48 ++++++++++++++++++++++++++++++++++++++- drivers/scsi/ufs/ufshcd.h | 4 ++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index a6a4a4302ca9..0da9e16317f5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -970,6 +970,41 @@ static ssize_t ufshcd_clkgate_delay_store(struct device *dev, return count; } +static ssize_t ufshcd_clkgate_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", hba->clk_gating.is_enabled); +} + +static ssize_t ufshcd_clkgate_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + unsigned long flags; + u32 value; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + value = !!value; + if (value == hba->clk_gating.is_enabled) + goto out; + + if (value) { + ufshcd_release(hba); + } else { + spin_lock_irqsave(hba->host->host_lock, flags); + hba->clk_gating.active_reqs++; + spin_unlock_irqrestore(hba->host->host_lock, flags); + } + + hba->clk_gating.is_enabled = value; +out: + return count; +} + static void ufshcd_init_clk_gating(struct ufs_hba *hba) { if (!ufshcd_is_clkgating_allowed(hba)) @@ -979,13 +1014,23 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba) INIT_DELAYED_WORK(&hba->clk_gating.gate_work, ufshcd_gate_work); INIT_WORK(&hba->clk_gating.ungate_work, ufshcd_ungate_work); + hba->clk_gating.is_enabled = true; + hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show; hba->clk_gating.delay_attr.store = ufshcd_clkgate_delay_store; sysfs_attr_init(&hba->clk_gating.delay_attr.attr); hba->clk_gating.delay_attr.attr.name = "clkgate_delay_ms"; - hba->clk_gating.delay_attr.attr.mode = S_IRUGO | S_IWUSR; + hba->clk_gating.delay_attr.attr.mode = 0644; if (device_create_file(hba->dev, &hba->clk_gating.delay_attr)) dev_err(hba->dev, "Failed to create sysfs for clkgate_delay\n"); + + hba->clk_gating.enable_attr.show = ufshcd_clkgate_enable_show; + hba->clk_gating.enable_attr.store = ufshcd_clkgate_enable_store; + sysfs_attr_init(&hba->clk_gating.enable_attr.attr); + hba->clk_gating.enable_attr.attr.name = "clkgate_enable"; + hba->clk_gating.enable_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->clk_gating.enable_attr)) + dev_err(hba->dev, "Failed to create sysfs for clkgate_enable\n"); } static void ufshcd_exit_clk_gating(struct ufs_hba *hba) @@ -993,6 +1038,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) if (!ufshcd_is_clkgating_allowed(hba)) return; device_remove_file(hba->dev, &hba->clk_gating.delay_attr); + device_remove_file(hba->dev, &hba->clk_gating.enable_attr); cancel_work_sync(&hba->clk_gating.ungate_work); cancel_delayed_work_sync(&hba->clk_gating.gate_work); } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 08cd26ed2382..0882ba67ccb1 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -320,6 +320,8 @@ enum clk_gating_state { * @is_suspended: clk gating is suspended when set to 1 which can be used * during suspend/resume * @delay_attr: sysfs attribute to control delay_attr + * @enable_attr: sysfs attribute to enable/disable clock gating + * @is_enabled: Indicates the current status of clock gating * @active_reqs: number of requests that are pending and should be waited for * completion before gating clocks. */ @@ -330,6 +332,8 @@ struct ufs_clk_gating { unsigned long delay_ms; bool is_suspended; struct device_attribute delay_attr; + struct device_attribute enable_attr; + bool is_enabled; int active_reqs; }; From fcb0c4b08a18fe35c3adc594d3edc8e335ff7960 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Thu, 22 Dec 2016 18:40:50 -0800 Subject: [PATCH 0240/1587] scsi: ufs: Add sysfs node to dynamically control clock scaling Provide an option to enable/disable clock scaling during runtime. Write 1/0 to "clkscale_enable" sysfs node to enable/disable clock scaling. Signed-off-by: Sahitya Tummala Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 95 ++++++++++++++++++++++++++++++++------- drivers/scsi/ufs/ufshcd.h | 4 +- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0da9e16317f5..4468ba059696 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -230,6 +230,9 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); +static void ufshcd_resume_clkscaling(struct ufs_hba *hba); +static void ufshcd_suspend_clkscaling(struct ufs_hba *hba); +static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up); static irqreturn_t ufshcd_intr(int irq, void *__hba); static int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode); @@ -713,16 +716,58 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba) static void ufshcd_suspend_clkscaling(struct ufs_hba *hba) { - if (ufshcd_is_clkscaling_enabled(hba)) { - devfreq_suspend_device(hba->devfreq); - hba->clk_scaling.window_start_t = 0; - } + if (!ufshcd_is_clkscaling_supported(hba)) + return; + + devfreq_suspend_device(hba->devfreq); + hba->clk_scaling.window_start_t = 0; } static void ufshcd_resume_clkscaling(struct ufs_hba *hba) { - if (ufshcd_is_clkscaling_enabled(hba)) - devfreq_resume_device(hba->devfreq); + devfreq_resume_device(hba->devfreq); +} + +static ssize_t ufshcd_clkscale_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", hba->clk_scaling.is_allowed); +} + +static ssize_t ufshcd_clkscale_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + u32 value; + int err; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + value = !!value; + if (value == hba->clk_scaling.is_allowed) + goto out; + + pm_runtime_get_sync(hba->dev); + ufshcd_hold(hba, false); + + if (value) { + ufshcd_resume_clkscaling(hba); + } else { + ufshcd_suspend_clkscaling(hba); + err = ufshcd_scale_clks(hba, true); + if (err) + dev_err(hba->dev, "%s: failed to scale clocks up %d\n", + __func__, err); + } + hba->clk_scaling.is_allowed = value; + + ufshcd_release(hba); + pm_runtime_put_sync(hba->dev); +out: + return count; } static void ufshcd_ungate_work(struct work_struct *work) @@ -758,7 +803,8 @@ static void ufshcd_ungate_work(struct work_struct *work) hba->clk_gating.is_suspended = false; } unblock_reqs: - ufshcd_resume_clkscaling(hba); + if (hba->clk_scaling.is_allowed) + ufshcd_resume_clkscaling(hba); scsi_unblock_requests(hba->host); } @@ -1046,7 +1092,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) /* Must be called with host lock acquired */ static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba) { - if (!ufshcd_is_clkscaling_enabled(hba)) + if (!ufshcd_is_clkscaling_supported(hba)) return; if (!hba->clk_scaling.is_busy_started) { @@ -1059,7 +1105,7 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba) { struct ufs_clk_scaling *scaling = &hba->clk_scaling; - if (!ufshcd_is_clkscaling_enabled(hba)) + if (!ufshcd_is_clkscaling_supported(hba)) return; if (!hba->outstanding_reqs && scaling->is_busy_started) { @@ -5526,12 +5572,15 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) pm_runtime_put_sync(hba->dev); } + /* Resume devfreq after UFS device is detected */ + if (ufshcd_is_clkscaling_supported(hba)) { + ufshcd_resume_clkscaling(hba); + hba->clk_scaling.is_allowed = true; + } + if (!hba->is_init_prefetch) hba->is_init_prefetch = true; - /* Resume devfreq after UFS device is detected */ - ufshcd_resume_clkscaling(hba); - out: /* * If we failed to initialize the device or the device is not @@ -6484,7 +6533,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufshcd_urgent_bkops(hba); hba->clk_gating.is_suspended = false; - ufshcd_resume_clkscaling(hba); + if (hba->clk_scaling.is_allowed) + ufshcd_resume_clkscaling(hba); /* Schedule clock gating in case of no access to UFS device yet */ ufshcd_release(hba); @@ -6702,6 +6752,8 @@ void ufshcd_remove(struct ufs_hba *hba) ufshcd_hba_stop(hba, true); ufshcd_exit_clk_gating(hba); + if (ufshcd_is_clkscaling_supported(hba)) + device_remove_file(hba->dev, &hba->clk_scaling.enable_attr); ufshcd_hba_exit(hba); } EXPORT_SYMBOL_GPL(ufshcd_remove); @@ -6835,7 +6887,7 @@ static int ufshcd_devfreq_target(struct device *dev, bool release_clk_hold = false; unsigned long irq_flags; - if (!ufshcd_is_clkscaling_enabled(hba)) + if (!ufshcd_is_clkscaling_supported(hba)) return -EINVAL; spin_lock_irqsave(hba->host->host_lock, irq_flags); @@ -6883,7 +6935,7 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev, struct ufs_clk_scaling *scaling = &hba->clk_scaling; unsigned long flags; - if (!ufshcd_is_clkscaling_enabled(hba)) + if (!ufshcd_is_clkscaling_supported(hba)) return -EINVAL; memset(stat, 0, sizeof(*stat)); @@ -6919,6 +6971,16 @@ static struct devfreq_dev_profile ufs_devfreq_profile = { .target = ufshcd_devfreq_target, .get_dev_status = ufshcd_devfreq_get_dev_status, }; +static void ufshcd_clkscaling_init_sysfs(struct ufs_hba *hba) +{ + hba->clk_scaling.enable_attr.show = ufshcd_clkscale_enable_show; + hba->clk_scaling.enable_attr.store = ufshcd_clkscale_enable_store; + sysfs_attr_init(&hba->clk_scaling.enable_attr.attr); + hba->clk_scaling.enable_attr.attr.name = "clkscale_enable"; + hba->clk_scaling.enable_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->clk_scaling.enable_attr)) + dev_err(hba->dev, "Failed to create sysfs for clkscale_enable\n"); +} /** * ufshcd_init - Driver initialization routine @@ -7045,7 +7107,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) goto out_remove_scsi_host; } - if (ufshcd_is_clkscaling_enabled(hba)) { + if (ufshcd_is_clkscaling_supported(hba)) { hba->devfreq = devm_devfreq_add_device(dev, &ufs_devfreq_profile, "simple_ondemand", NULL); if (IS_ERR(hba->devfreq)) { @@ -7056,6 +7118,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) } /* Suspend devfreq until the UFS device is detected */ ufshcd_suspend_clkscaling(hba); + ufshcd_clkscaling_init_sysfs(hba); } /* Hold auto suspend until async scan completes */ diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 0882ba67ccb1..bdd2284967f2 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -342,6 +342,8 @@ struct ufs_clk_scaling { bool is_busy_started; unsigned long tot_busy_t; unsigned long window_start_t; + struct device_attribute enable_attr; + bool is_allowed; }; /** @@ -580,7 +582,7 @@ static inline bool ufshcd_can_hibern8_during_gating(struct ufs_hba *hba) { return hba->caps & UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; } -static inline int ufshcd_is_clkscaling_enabled(struct ufs_hba *hba) +static inline int ufshcd_is_clkscaling_supported(struct ufs_hba *hba) { return hba->caps & UFSHCD_CAP_CLK_SCALING; } From 09690d5a6ae1b7e4cb5ac429c311b99d09352c12 Mon Sep 17 00:00:00 2001 From: "subhashj@codeaurora.org" Date: Thu, 22 Dec 2016 18:41:00 -0800 Subject: [PATCH 0241/1587] scsi: ufs: provide sysfs attribute to select the PM level This patch provides the sysfs attribute to choose the power management level for UFS runtime and system suspend. Reviewed-by: Sujit Reddy Thumma Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 144 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 2 + 2 files changed, 146 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 4468ba059696..3036f606545d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -686,6 +686,28 @@ static inline int ufshcd_is_hba_active(struct ufs_hba *hba) return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1; } +static const char *ufschd_uic_link_state_to_string( + enum uic_link_state state) +{ + switch (state) { + case UIC_LINK_OFF_STATE: return "OFF"; + case UIC_LINK_ACTIVE_STATE: return "ACTIVE"; + case UIC_LINK_HIBERN8_STATE: return "HIBERN8"; + default: return "UNKNOWN"; + } +} + +static const char *ufschd_ufs_dev_pwr_mode_to_string( + enum ufs_dev_pwr_mode state) +{ + switch (state) { + case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; + case UFS_SLEEP_PWR_MODE: return "SLEEP"; + case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; + default: return "UNKNOWN"; + } +} + u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba) { /* HCI version 1.0 and 1.1 supports UniPro 1.41 */ @@ -6709,6 +6731,127 @@ int ufshcd_runtime_idle(struct ufs_hba *hba) } EXPORT_SYMBOL(ufshcd_runtime_idle); +static inline ssize_t ufshcd_pm_lvl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, + bool rpm) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + unsigned long flags, value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX)) + return -EINVAL; + + spin_lock_irqsave(hba->host->host_lock, flags); + if (rpm) + hba->rpm_lvl = value; + else + hba->spm_lvl = value; + spin_unlock_irqrestore(hba->host->host_lock, flags); + return count; +} + +static ssize_t ufshcd_rpm_lvl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + int curr_len; + u8 lvl; + + curr_len = snprintf(buf, PAGE_SIZE, + "\nCurrent Runtime PM level [%d] => dev_state [%s] link_state [%s]\n", + hba->rpm_lvl, + ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[hba->rpm_lvl].dev_state), + ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[hba->rpm_lvl].link_state)); + + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), + "\nAll available Runtime PM levels info:\n"); + for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), + "\tRuntime PM level [%d] => dev_state [%s] link_state [%s]\n", + lvl, + ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[lvl].dev_state), + ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[lvl].link_state)); + + return curr_len; +} + +static ssize_t ufshcd_rpm_lvl_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ufshcd_pm_lvl_store(dev, attr, buf, count, true); +} + +static void ufshcd_add_rpm_lvl_sysfs_nodes(struct ufs_hba *hba) +{ + hba->rpm_lvl_attr.show = ufshcd_rpm_lvl_show; + hba->rpm_lvl_attr.store = ufshcd_rpm_lvl_store; + sysfs_attr_init(&hba->rpm_lvl_attr.attr); + hba->rpm_lvl_attr.attr.name = "rpm_lvl"; + hba->rpm_lvl_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->rpm_lvl_attr)) + dev_err(hba->dev, "Failed to create sysfs for rpm_lvl\n"); +} + +static ssize_t ufshcd_spm_lvl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + int curr_len; + u8 lvl; + + curr_len = snprintf(buf, PAGE_SIZE, + "\nCurrent System PM level [%d] => dev_state [%s] link_state [%s]\n", + hba->spm_lvl, + ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[hba->spm_lvl].dev_state), + ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[hba->spm_lvl].link_state)); + + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), + "\nAll available System PM levels info:\n"); + for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), + "\tSystem PM level [%d] => dev_state [%s] link_state [%s]\n", + lvl, + ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[lvl].dev_state), + ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[lvl].link_state)); + + return curr_len; +} + +static ssize_t ufshcd_spm_lvl_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ufshcd_pm_lvl_store(dev, attr, buf, count, false); +} + +static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba) +{ + hba->spm_lvl_attr.show = ufshcd_spm_lvl_show; + hba->spm_lvl_attr.store = ufshcd_spm_lvl_store; + sysfs_attr_init(&hba->spm_lvl_attr.attr); + hba->spm_lvl_attr.attr.name = "spm_lvl"; + hba->spm_lvl_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->spm_lvl_attr)) + dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n"); +} + +static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba) +{ + ufshcd_add_rpm_lvl_sysfs_nodes(hba); + ufshcd_add_spm_lvl_sysfs_nodes(hba); +} + /** * ufshcd_shutdown - shutdown routine * @hba: per adapter instance @@ -7133,6 +7276,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_set_ufs_dev_active(hba); async_schedule(ufshcd_async_scan, hba); + ufshcd_add_sysfs_nodes(hba); return 0; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index bdd2284967f2..787323be0919 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -435,6 +435,8 @@ struct ufs_hba { enum ufs_pm_level rpm_lvl; /* Desired UFS power management level during system PM */ enum ufs_pm_level spm_lvl; + struct device_attribute rpm_lvl_attr; + struct device_attribute spm_lvl_attr; int pm_op_in_progress; struct ufshcd_lrb *lrb; From 0c8f75869ed8941fcbf21643fced7bc652f68f14 Mon Sep 17 00:00:00 2001 From: "subhashj@codeaurora.org" Date: Thu, 22 Dec 2016 18:41:11 -0800 Subject: [PATCH 0242/1587] scsi: ufs: set default UFS power management level UFS device and link can be put in multiple different low power modes hence UFS driver supports multiple different low power modes. This change sets the default UFS power management level which should put the link hibernate state and device in sleep state. This default power management level gives good power savings with relatively less enter/exit latencies. Reviewed-by: Yaniv Gardi Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3036f606545d..9c16e08c3742 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -191,6 +191,22 @@ ufs_get_pm_lvl_to_link_pwr_state(enum ufs_pm_level lvl) return ufs_pm_lvl_states[lvl].link_state; } +static inline enum ufs_pm_level +ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state, + enum uic_link_state link_state) +{ + enum ufs_pm_level lvl; + + for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) { + if ((ufs_pm_lvl_states[lvl].dev_state == dev_state) && + (ufs_pm_lvl_states[lvl].link_state == link_state)) + return lvl; + } + + /* if no match found, return the level 0 */ + return UFS_PM_LVL_0; +} + static struct ufs_dev_fix ufs_fixups[] = { /* UFS cards deviations table */ UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, @@ -7264,6 +7280,18 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_clkscaling_init_sysfs(hba); } + /* + * Set the default power management level for runtime and system PM. + * Default power saving mode is to keep UFS link in Hibern8 state + * and UFS device in sleep state. + */ + hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state( + UFS_SLEEP_PWR_MODE, + UIC_LINK_HIBERN8_STATE); + hba->spm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state( + UFS_SLEEP_PWR_MODE, + UIC_LINK_HIBERN8_STATE); + /* Hold auto suspend until async scan completes */ pm_runtime_get_sync(dev); From 4e768e7645ec4ffa92ee163643777b261ae97142 Mon Sep 17 00:00:00 2001 From: "subhashj@codeaurora.org" Date: Thu, 22 Dec 2016 18:41:22 -0800 Subject: [PATCH 0243/1587] scsi: ufs: add capability to keep auto bkops always enabled UFS device requires to perform bkops (back ground operations) periodically but host can control (via auto-bkops parameter of device) when device can perform bkops based on its performance requirements. In general, host would like to enable the device's auto-bkops only when it's not doing any regular data transfer but sometimes device may not behave properly if host keeps the auto-bkops disabled. This change adds the capability to let the device auto-bkops always enabled except suspend. Reviewed-by: Sahitya Tummala Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 33 ++++++++++++++++++++++----------- drivers/scsi/ufs/ufshcd.h | 13 +++++++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9c16e08c3742..10840306f663 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4134,18 +4134,25 @@ out: } /** - * ufshcd_force_reset_auto_bkops - force enable of auto bkops + * ufshcd_force_reset_auto_bkops - force reset auto bkops state * @hba: per adapter instance * * After a device reset the device may toggle the BKOPS_EN flag * to default value. The s/w tracking variables should be updated - * as well. Do this by forcing enable of auto bkops. + * as well. This function would change the auto-bkops state based on + * UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND. */ -static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba) +static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba) { - hba->auto_bkops_enabled = false; - hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS; - ufshcd_enable_auto_bkops(hba); + if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) { + hba->auto_bkops_enabled = false; + hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS; + ufshcd_enable_auto_bkops(hba); + } else { + hba->auto_bkops_enabled = true; + hba->ee_ctrl_mask &= ~MASK_EE_URGENT_BKOPS; + ufshcd_disable_auto_bkops(hba); + } } static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status) @@ -6564,11 +6571,15 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto set_old_link_state; } - /* - * If BKOPs operations are urgently needed at this moment then - * keep auto-bkops enabled or else disable it. - */ - ufshcd_urgent_bkops(hba); + if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) + ufshcd_enable_auto_bkops(hba); + else + /* + * If BKOPs operations are urgently needed at this moment then + * keep auto-bkops enabled or else disable it. + */ + ufshcd_urgent_bkops(hba); + hba->clk_gating.is_suspended = false; if (hba->clk_scaling.is_allowed) diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 787323be0919..f25d4684ef0e 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -566,6 +566,14 @@ struct ufs_hba { * CAUTION: Enabling this might reduce overall UFS throughput. */ #define UFSHCD_CAP_INTR_AGGR (1 << 4) + /* + * This capability allows the device auto-bkops to be always enabled + * except during suspend (both runtime and suspend). + * Enabling this capability means that device will always be allowed + * to do background operation when it's active but it might degrade + * the performance of ongoing read/write operations. + */ +#define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5) struct devfreq *devfreq; struct ufs_clk_scaling clk_scaling; @@ -663,6 +671,11 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba) BUG_ON(!hba); return hba->priv; } +static inline bool ufshcd_keep_autobkops_enabled_except_suspend( + struct ufs_hba *hba) +{ + return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND; +} extern int ufshcd_runtime_suspend(struct ufs_hba *hba); extern int ufshcd_runtime_resume(struct ufs_hba *hba); From d2aebb9b269b3e094b2d2d03121c3863b683a25b Mon Sep 17 00:00:00 2001 From: "subhashj@codeaurora.org" Date: Thu, 22 Dec 2016 18:41:33 -0800 Subject: [PATCH 0244/1587] scsi: ufs: fix setting init power mode Immediately after successful UFS link startup, UFS link power mode would be in PWM-G1, 1-lane, SLOW-AUTO mode. But currently we are doing few of the DME local/peer attributes access before setting the "hba->pwr_info" to default power mode. If we are doing link startup as part of error recovery then old power mode might be set to FAST mode and doing DME peer access (after link startup but before updating "hba->pwr_info" to default power mode) unintentionally tries to switch from FAST to FAST_AUTO mode (if UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE quirk is enabled). Above issue is fixed by setting the default power mode immediately after successful link startup. Reviewed-by: Sahitya Tummala Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 10840306f663..184106fa21da 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3512,6 +3512,10 @@ link_startup: goto link_startup; } + /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ + ufshcd_init_pwr_info(hba); + ufshcd_print_pwr_info(hba); + if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) { ret = ufshcd_disable_device_tx_lcc(hba); if (ret) @@ -5547,9 +5551,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; - ufshcd_init_pwr_info(hba); - ufshcd_print_pwr_info(hba); - /* set the default level for urgent bkops */ hba->urgent_bkops_lvl = BKOPS_STATUS_PERF_IMPACT; hba->is_urgent_bkops_lvl_checked = false; From 911a0771b6fa7bac5eae753c17c87ecb77c77283 Mon Sep 17 00:00:00 2001 From: "subhashj@codeaurora.org" Date: Thu, 22 Dec 2016 18:41:48 -0800 Subject: [PATCH 0245/1587] scsi: ufs: add time profiling support This patch adds the profiling support for some of the time critical operations like hibern8 enter/exit, clock gating & clock scaling. Reviewed-by: Venkat Gopalakrishnan Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 24 +++++++++++++++++++++++ include/trace/events/ufs.h | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 184106fa21da..58c4df405528 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3021,11 +3021,14 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) { int ret; struct uic_command uic_cmd = {0}; + ktime_t start = ktime_get(); ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_ENTER, PRE_CHANGE); uic_cmd.command = UIC_CMD_DME_HIBER_ENTER; ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter", + ktime_to_us(ktime_sub(ktime_get(), start)), ret); if (ret) { dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d\n", @@ -3061,11 +3064,15 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) { struct uic_command uic_cmd = {0}; int ret; + ktime_t start = ktime_get(); ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_EXIT, PRE_CHANGE); uic_cmd.command = UIC_CMD_DME_HIBER_EXIT; ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit", + ktime_to_us(ktime_sub(ktime_get(), start)), ret); + if (ret) { dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d\n", __func__, ret); @@ -5950,6 +5957,8 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, struct ufs_clk_info *clki; struct list_head *head = &hba->clk_list_head; unsigned long flags; + ktime_t start = ktime_get(); + bool clk_state_changed = false; if (!head || list_empty(head)) goto out; @@ -5963,6 +5972,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, if (skip_ref_clk && !strcmp(clki->name, "ref_clk")) continue; + clk_state_changed = on ^ clki->enabled; if (on && !clki->enabled) { ret = clk_prepare_enable(clki->clk); if (ret) { @@ -5997,6 +6007,10 @@ out: spin_unlock_irqrestore(hba->host->host_lock, flags); } + if (clk_state_changed) + trace_ufshcd_profile_clk_gating(dev_name(hba->dev), + (on ? "on" : "off"), + ktime_to_us(ktime_sub(ktime_get(), start)), ret); return ret; } @@ -6996,6 +7010,8 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) int ret = 0; struct ufs_clk_info *clki; struct list_head *head = &hba->clk_list_head; + ktime_t start = ktime_get(); + bool clk_state_changed = false; if (!head || list_empty(head)) goto out; @@ -7009,6 +7025,8 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) if (scale_up && clki->max_freq) { if (clki->curr_freq == clki->max_freq) continue; + + clk_state_changed = true; ret = clk_set_rate(clki->clk, clki->max_freq); if (ret) { dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n", @@ -7026,6 +7044,8 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) } else if (!scale_up && clki->min_freq) { if (clki->curr_freq == clki->min_freq) continue; + + clk_state_changed = true; ret = clk_set_rate(clki->clk, clki->min_freq); if (ret) { dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n", @@ -7047,6 +7067,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE); out: + if (clk_state_changed) + trace_ufshcd_profile_clk_scaling(dev_name(hba->dev), + (scale_up ? "up" : "down"), + ktime_to_us(ktime_sub(ktime_get(), start)), ret); return ret; } diff --git a/include/trace/events/ufs.h b/include/trace/events/ufs.h index 57743b6ed0b0..e9634dff51a8 100644 --- a/include/trace/events/ufs.h +++ b/include/trace/events/ufs.h @@ -123,6 +123,46 @@ TRACE_EVENT(ufshcd_auto_bkops_state, __get_str(dev_name), __get_str(state)) ); +DECLARE_EVENT_CLASS(ufshcd_profiling_template, + TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us, + int err), + + TP_ARGS(dev_name, profile_info, time_us, err), + + TP_STRUCT__entry( + __string(dev_name, dev_name) + __string(profile_info, profile_info) + __field(s64, time_us) + __field(int, err) + ), + + TP_fast_assign( + __assign_str(dev_name, dev_name); + __assign_str(profile_info, profile_info); + __entry->time_us = time_us; + __entry->err = err; + ), + + TP_printk("%s: %s: took %lld usecs, err %d", + __get_str(dev_name), __get_str(profile_info), + __entry->time_us, __entry->err) +); + +DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_hibern8, + TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us, + int err), + TP_ARGS(dev_name, profile_info, time_us, err)); + +DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_gating, + TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us, + int err), + TP_ARGS(dev_name, profile_info, time_us, err)); + +DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_scaling, + TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us, + int err), + TP_ARGS(dev_name, profile_info, time_us, err)); + DECLARE_EVENT_CLASS(ufshcd_template, TP_PROTO(const char *dev_name, int err, s64 usecs, int dev_state, int link_state), From 1a07f2d96eb9085396cbfb2d6d42d4003aa2934a Mon Sep 17 00:00:00 2001 From: Lee Susman Date: Thu, 22 Dec 2016 18:42:03 -0800 Subject: [PATCH 0246/1587] scsi: ufs: add trace event for ufs commands Use the ftrace infrastructure to conditionally trace ufs command events. New trace event is created, which samples the following ufs command data: - device name - optional identification string - task tag - doorbell register - number of transfer bytes - interrupt status register - request start LBA - command opcode Currently we only fully trace read(10) and write(10) commands. All other commands which pass through ufshcd_send_command() will be printed with "-1" in the lba and transfer_len fields. Usage: echo 1 > /sys/kernel/debug/tracing/events/ufs/enable cat /sys/kernel/debug/tracing/trace_pipe Signed-off-by: Lee Susman Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 42 +++++++++++++++++++++++++++++++++++++- include/trace/events/ufs.h | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 58c4df405528..2c88757eb701 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -293,6 +293,41 @@ static inline void ufshcd_remove_non_printable(char *val) *val = ' '; } +static void ufshcd_add_command_trace(struct ufs_hba *hba, + unsigned int tag, const char *str) +{ + sector_t lba = -1; + u8 opcode = 0; + u32 intr, doorbell; + struct ufshcd_lrb *lrbp; + int transfer_len = -1; + + if (!trace_ufshcd_command_enabled()) + return; + + lrbp = &hba->lrb[tag]; + + if (lrbp->cmd) { /* data phase exists */ + opcode = (u8)(*lrbp->cmd->cmnd); + if ((opcode == READ_10) || (opcode == WRITE_10)) { + /* + * Currently we only fully trace read(10) and write(10) + * commands + */ + if (lrbp->cmd->request && lrbp->cmd->request->bio) + lba = + lrbp->cmd->request->bio->bi_iter.bi_sector; + transfer_len = be32_to_cpu( + lrbp->ucd_req_ptr->sc.exp_data_transfer_len); + } + } + + intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); + doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); + trace_ufshcd_command(dev_name(hba->dev), str, tag, + doorbell, transfer_len, intr, lba, opcode); +} + static void ufshcd_print_host_regs(struct ufs_hba *hba) { /* @@ -1166,6 +1201,7 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); /* Make sure that doorbell is committed immediately */ wmb(); + ufshcd_add_command_trace(hba, task_tag, "send"); } /** @@ -3955,6 +3991,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, lrbp = &hba->lrb[index]; cmd = lrbp->cmd; if (cmd) { + ufshcd_add_command_trace(hba, index, "complete"); result = ufshcd_transfer_rsp_status(hba, lrbp); scsi_dma_unmap(cmd); cmd->result = result; @@ -3966,8 +4003,11 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, __ufshcd_release(hba); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { - if (hba->dev_cmd.complete) + if (hba->dev_cmd.complete) { + ufshcd_add_command_trace(hba, index, + "dev_complete"); complete(hba->dev_cmd.complete); + } } } diff --git a/include/trace/events/ufs.h b/include/trace/events/ufs.h index e9634dff51a8..bf6f82673492 100644 --- a/include/trace/events/ufs.h +++ b/include/trace/events/ufs.h @@ -219,6 +219,44 @@ DEFINE_EVENT(ufshcd_template, ufshcd_init, TP_PROTO(const char *dev_name, int err, s64 usecs, int dev_state, int link_state), TP_ARGS(dev_name, err, usecs, dev_state, link_state)); + +TRACE_EVENT(ufshcd_command, + TP_PROTO(const char *dev_name, const char *str, unsigned int tag, + u32 doorbell, int transfer_len, u32 intr, u64 lba, + u8 opcode), + + TP_ARGS(dev_name, str, tag, doorbell, transfer_len, intr, lba, opcode), + + TP_STRUCT__entry( + __string(dev_name, dev_name) + __string(str, str) + __field(unsigned int, tag) + __field(u32, doorbell) + __field(int, transfer_len) + __field(u32, intr) + __field(u64, lba) + __field(u8, opcode) + ), + + TP_fast_assign( + __assign_str(dev_name, dev_name); + __assign_str(str, str); + __entry->tag = tag; + __entry->doorbell = doorbell; + __entry->transfer_len = transfer_len; + __entry->intr = intr; + __entry->lba = lba; + __entry->opcode = opcode; + ), + + TP_printk( + "%s: %s: tag: %u, DB: 0x%x, size: %d, IS: %u, LBA: %llu, opcode: 0x%x", + __get_str(str), __get_str(dev_name), __entry->tag, + __entry->doorbell, __entry->transfer_len, + __entry->intr, __entry->lba, (u32)__entry->opcode + ) +); + #endif /* if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ) */ /* This part must be outside protection */ From ff8e20c66249210563aaea5382b08c94933f720d Mon Sep 17 00:00:00 2001 From: Dolev Raviv Date: Thu, 22 Dec 2016 18:42:18 -0800 Subject: [PATCH 0247/1587] scsi: ufs: Improve fatal error logs Errors such as UIC error, illegal OCS values, and others may require more information for debugging. Such information could be hibern8 events, events sequences, recoverable errors, error history, and more. This patch improves tracking of important errors and events in debug level to be enabled when debugging a such issues. It includes: * UIC error history * Successful hibern8 events * Successful command after hibern8 exit * Clk-freq info * Failed device command * Infrastructure for dumping host controller debug information Signed-off-by: Dolev Raviv Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 203 ++++++++++++++++++++++++++++++-------- drivers/scsi/ufs/ufshcd.h | 47 +++++++++ 2 files changed, 208 insertions(+), 42 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2c88757eb701..be6322e38d74 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -328,6 +328,37 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, doorbell, transfer_len, intr, lba, opcode); } +static void ufshcd_print_clk_freqs(struct ufs_hba *hba) +{ + struct ufs_clk_info *clki; + struct list_head *head = &hba->clk_list_head; + + if (!head || list_empty(head)) + return; + + list_for_each_entry(clki, head, list) { + if (!IS_ERR_OR_NULL(clki->clk) && clki->min_freq && + clki->max_freq) + dev_err(hba->dev, "clk: %s, rate: %u\n", + clki->name, clki->curr_freq); + } +} + +static void ufshcd_print_uic_err_hist(struct ufs_hba *hba, + struct ufs_uic_err_reg_hist *err_hist, char *err_name) +{ + int i; + + for (i = 0; i < UIC_ERR_REG_HIST_LENGTH; i++) { + int p = (i + err_hist->pos - 1) % UIC_ERR_REG_HIST_LENGTH; + + if (err_hist->reg[p] == 0) + continue; + dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, i, + err_hist->reg[p], ktime_to_us(err_hist->tstamp[p])); + } +} + static void ufshcd_print_host_regs(struct ufs_hba *hba) { /* @@ -344,6 +375,21 @@ static void ufshcd_print_host_regs(struct ufs_hba *hba) dev_err(hba->dev, "hba->outstanding_reqs = 0x%x, hba->outstanding_tasks = 0x%x\n", (u32)hba->outstanding_reqs, (u32)hba->outstanding_tasks); + dev_err(hba->dev, + "last_hibern8_exit_tstamp at %lld us, hibern8_exit_cnt = %d\n", + ktime_to_us(hba->ufs_stats.last_hibern8_exit_tstamp), + hba->ufs_stats.hibern8_exit_cnt); + + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.pa_err, "pa_err"); + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.dl_err, "dl_err"); + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.nl_err, "nl_err"); + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.tl_err, "tl_err"); + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.dme_err, "dme_err"); + + ufshcd_print_clk_freqs(hba); + + if (hba->vops && hba->vops->dbg_register_dump) + hba->vops->dbg_register_dump(hba); } static @@ -355,22 +401,30 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) for_each_set_bit(tag, &bitmap, hba->nutrs) { lrbp = &hba->lrb[tag]; - dev_err(hba->dev, "UPIU[%d] - Transfer Request Descriptor\n", - tag); + dev_err(hba->dev, "UPIU[%d] - issue time %lld us\n", + tag, ktime_to_us(lrbp->issue_time_stamp)); + dev_err(hba->dev, + "UPIU[%d] - Transfer Request Descriptor phys@0x%llx\n", + tag, (u64)lrbp->utrd_dma_addr); + ufshcd_hex_dump("UPIU TRD: ", lrbp->utr_descriptor_ptr, sizeof(struct utp_transfer_req_desc)); - dev_err(hba->dev, "UPIU[%d] - Request UPIU\n", tag); + dev_err(hba->dev, "UPIU[%d] - Request UPIU phys@0x%llx\n", tag, + (u64)lrbp->ucd_req_dma_addr); ufshcd_hex_dump("UPIU REQ: ", lrbp->ucd_req_ptr, sizeof(struct utp_upiu_req)); - dev_err(hba->dev, "UPIU[%d] - Response UPIU\n", tag); + dev_err(hba->dev, "UPIU[%d] - Response UPIU phys@0x%llx\n", tag, + (u64)lrbp->ucd_rsp_dma_addr); ufshcd_hex_dump("UPIU RSP: ", lrbp->ucd_rsp_ptr, sizeof(struct utp_upiu_rsp)); if (pr_prdt) { int prdt_length = le16_to_cpu( lrbp->utr_descriptor_ptr->prd_table_length); - dev_err(hba->dev, "UPIU[%d] - PRDT - %d entries\n", tag, - prdt_length); + dev_err(hba->dev, + "UPIU[%d] - PRDT - %d entries phys@0x%llx\n", + tag, prdt_length, + (u64)lrbp->ucd_prdt_dma_addr); ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr, sizeof(struct ufshcd_sg_entry) * prdt_length); @@ -399,6 +453,32 @@ static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap) } } +/** + * ufshcd_print_pwr_info - print power params as saved in hba + * power info + * @hba: per-adapter instance + */ +static void ufshcd_print_pwr_info(struct ufs_hba *hba) +{ + static const char * const names[] = { + "INVALID MODE", + "FAST MODE", + "SLOW_MODE", + "INVALID MODE", + "FASTAUTO_MODE", + "SLOWAUTO_MODE", + "INVALID MODE", + }; + + dev_err(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", + __func__, + hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, + hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, + names[hba->pwr_info.pwr_rx], + names[hba->pwr_info.pwr_tx], + hba->pwr_info.hs_rate); +} + /* * ufshcd_wait_for_register - wait for register value to change * @hba - per-adapter interface @@ -1196,6 +1276,7 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba) static inline void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) { + hba->lrb[task_tag].issue_time_stamp = ktime_get(); ufshcd_clk_scaling_start_busy(hba); __set_bit(task_tag, &hba->outstanding_reqs); ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); @@ -1877,6 +1958,7 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) int resp; int err = 0; + hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr); switch (resp) { @@ -2646,32 +2728,6 @@ out: return -ENOMEM; } -/** - * ufshcd_print_pwr_info - print power params as saved in hba - * power info - * @hba: per-adapter instance - */ -static void ufshcd_print_pwr_info(struct ufs_hba *hba) -{ - static const char * const names[] = { - "INVALID MODE", - "FAST MODE", - "SLOW_MODE", - "INVALID MODE", - "FASTAUTO_MODE", - "SLOWAUTO_MODE", - "INVALID MODE", - }; - - dev_info(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", - __func__, - hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, - hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, - names[hba->pwr_info.pwr_rx], - names[hba->pwr_info.pwr_tx], - hba->pwr_info.hs_rate); -} - /** * ufshcd_host_memory_configure - configure local reference block with * memory offsets @@ -2734,12 +2790,19 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) } hba->lrb[i].utr_descriptor_ptr = (utrdlp + i); + hba->lrb[i].utrd_dma_addr = hba->utrdl_dma_addr + + (i * sizeof(struct utp_transfer_req_desc)); hba->lrb[i].ucd_req_ptr = (struct utp_upiu_req *)(cmd_descp + i); + hba->lrb[i].ucd_req_dma_addr = cmd_desc_element_addr; hba->lrb[i].ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; + hba->lrb[i].ucd_rsp_dma_addr = cmd_desc_element_addr + + response_offset; hba->lrb[i].ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp[i].prd_table; + hba->lrb[i].ucd_prdt_dma_addr = cmd_desc_element_addr + + prdt_offset; } } @@ -2763,7 +2826,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) ret = ufshcd_send_uic_cmd(hba, &uic_cmd); if (ret) - dev_err(hba->dev, + dev_dbg(hba->dev, "dme-link-startup: error code %d\n", ret); return ret; } @@ -3113,9 +3176,12 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d\n", __func__, ret); ret = ufshcd_link_recovery(hba); - } else + } else { ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_EXIT, POST_CHANGE); + hba->ufs_stats.last_hibern8_exit_tstamp = ktime_get(); + hba->ufs_stats.hibern8_exit_cnt++; + } return ret; } @@ -3885,7 +3951,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) switch (ocs) { case OCS_SUCCESS: result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr); - + hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); switch (result) { case UPIU_TRANSACTION_RESPONSE: /* @@ -3946,7 +4012,9 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) default: result |= DID_ERROR << 16; dev_err(hba->dev, - "OCS error from controller = %x\n", ocs); + "OCS error from controller = %x for tag %d\n", + ocs, lrbp->task_tag); + ufshcd_print_host_regs(hba); break; } /* end of switch */ @@ -4555,6 +4623,14 @@ out: pm_runtime_put_sync(hba->dev); } +static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist, + u32 reg) +{ + reg_hist->reg[reg_hist->pos] = reg; + reg_hist->tstamp[reg_hist->pos] = ktime_get(); + reg_hist->pos = (reg_hist->pos + 1) % UIC_ERR_REG_HIST_LENGTH; +} + /** * ufshcd_update_uic_error - check and set fatal UIC error flags. * @hba: per-adapter instance @@ -4567,15 +4643,20 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); /* Ignore LINERESET indication, as this is not an error */ if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && - (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) + (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) { /* * To know whether this error is fatal or not, DB timeout * must be checked but this error is handled separately. */ dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__); + ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg); + } /* PA_INIT_ERROR is fatal and needs UIC reset */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER); + if (reg) + ufshcd_update_uic_reg_hist(&hba->ufs_stats.dl_err, reg); + if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR; else if (hba->dev_quirks & @@ -4589,16 +4670,22 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) /* UIC NL/TL/DME errors needs software retry */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER); - if (reg) + if (reg) { + ufshcd_update_uic_reg_hist(&hba->ufs_stats.nl_err, reg); hba->uic_error |= UFSHCD_UIC_NL_ERROR; + } reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER); - if (reg) + if (reg) { + ufshcd_update_uic_reg_hist(&hba->ufs_stats.tl_err, reg); hba->uic_error |= UFSHCD_UIC_TL_ERROR; + } reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME); - if (reg) + if (reg) { + ufshcd_update_uic_reg_hist(&hba->ufs_stats.dme_err, reg); hba->uic_error |= UFSHCD_UIC_DME_ERROR; + } dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n", __func__, hba->uic_error); @@ -4965,12 +5052,16 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) UFS_QUERY_TASK, &resp); if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) { /* cmd pending in the device */ + dev_err(hba->dev, "%s: cmd pending in the device. tag = %d\n", + __func__, tag); break; } else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) { /* * cmd not pending in the device, check if it is * in transition. */ + dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n", + __func__, tag); reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); if (reg & (1 << tag)) { /* sleep for max. 200us to stabilize */ @@ -4978,8 +5069,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) continue; } /* command completed already */ + dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n", + __func__, tag); goto out; } else { + dev_err(hba->dev, + "%s: no response from device. tag = %d, err %d\n", + __func__, tag, err); if (!err) err = resp; /* service response error */ goto out; @@ -4994,14 +5090,20 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, UFS_ABORT_TASK, &resp); if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { - if (!err) + if (!err) { err = resp; /* service response error */ + dev_err(hba->dev, "%s: issued. tag = %d, err %d\n", + __func__, tag, err); + } goto out; } err = ufshcd_clear_cmd(hba, tag); - if (err) + if (err) { + dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n", + __func__, tag, err); goto out; + } scsi_dma_unmap(cmd); @@ -5583,6 +5685,20 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) ufshcd_vops_apply_dev_quirks(hba); } +static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) +{ + int err_reg_hist_size = sizeof(struct ufs_uic_err_reg_hist); + + hba->ufs_stats.hibern8_exit_cnt = 0; + hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); + + memset(&hba->ufs_stats.pa_err, 0, err_reg_hist_size); + memset(&hba->ufs_stats.dl_err, 0, err_reg_hist_size); + memset(&hba->ufs_stats.nl_err, 0, err_reg_hist_size); + memset(&hba->ufs_stats.tl_err, 0, err_reg_hist_size); + memset(&hba->ufs_stats.dme_err, 0, err_reg_hist_size); +} + /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance @@ -5602,6 +5718,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) hba->urgent_bkops_lvl = BKOPS_STATUS_PERF_IMPACT; hba->is_urgent_bkops_lvl_checked = false; + /* Debug counters initialization */ + ufshcd_clear_dbg_ufs_stats(hba); + /* UniPro link is active now */ ufshcd_set_link_active(hba); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index f25d4684ef0e..0ea49f982cac 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -152,6 +152,10 @@ struct ufs_pm_lvl_states { * @ucd_req_ptr: UCD address of the command * @ucd_rsp_ptr: Response UPIU address for this command * @ucd_prdt_ptr: PRDT address of the command + * @utrd_dma_addr: UTRD dma address for debug + * @ucd_prdt_dma_addr: PRDT dma address for debug + * @ucd_rsp_dma_addr: UPIU response dma address for debug + * @ucd_req_dma_addr: UPIU request dma address for debug * @cmd: pointer to SCSI command * @sense_buffer: pointer to sense buffer address of the SCSI command * @sense_bufflen: Length of the sense buffer @@ -160,6 +164,7 @@ struct ufs_pm_lvl_states { * @task_tag: Task tag of the command * @lun: LUN of the command * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation) + * @issue_time_stamp: time stamp for debug purposes */ struct ufshcd_lrb { struct utp_transfer_req_desc *utr_descriptor_ptr; @@ -167,6 +172,11 @@ struct ufshcd_lrb { struct utp_upiu_rsp *ucd_rsp_ptr; struct ufshcd_sg_entry *ucd_prdt_ptr; + dma_addr_t utrd_dma_addr; + dma_addr_t ucd_req_dma_addr; + dma_addr_t ucd_rsp_dma_addr; + dma_addr_t ucd_prdt_dma_addr; + struct scsi_cmnd *cmd; u8 *sense_buffer; unsigned int sense_bufflen; @@ -176,6 +186,7 @@ struct ufshcd_lrb { int task_tag; u8 lun; /* UPIU LUN id field is only 8-bit wide */ bool intr_cmd; + ktime_t issue_time_stamp; }; /** @@ -355,6 +366,41 @@ struct ufs_init_prefetch { u32 icc_level; }; +#define UIC_ERR_REG_HIST_LENGTH 8 +/** + * struct ufs_uic_err_reg_hist - keeps history of uic errors + * @pos: index to indicate cyclic buffer position + * @reg: cyclic buffer for registers value + * @tstamp: cyclic buffer for time stamp + */ +struct ufs_uic_err_reg_hist { + int pos; + u32 reg[UIC_ERR_REG_HIST_LENGTH]; + ktime_t tstamp[UIC_ERR_REG_HIST_LENGTH]; +}; + +/** + * struct ufs_stats - keeps usage/err statistics + * @hibern8_exit_cnt: Counter to keep track of number of exits, + * reset this after link-startup. + * @last_hibern8_exit_tstamp: Set time after the hibern8 exit. + * Clear after the first successful command completion. + * @pa_err: tracks pa-uic errors + * @dl_err: tracks dl-uic errors + * @nl_err: tracks nl-uic errors + * @tl_err: tracks tl-uic errors + * @dme_err: tracks dme errors + */ +struct ufs_stats { + u32 hibern8_exit_cnt; + ktime_t last_hibern8_exit_tstamp; + struct ufs_uic_err_reg_hist pa_err; + struct ufs_uic_err_reg_hist dl_err; + struct ufs_uic_err_reg_hist nl_err; + struct ufs_uic_err_reg_hist tl_err; + struct ufs_uic_err_reg_hist dme_err; +}; + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -531,6 +577,7 @@ struct ufs_hba { u32 uic_error; u32 saved_err; u32 saved_uic_err; + struct ufs_stats ufs_stats; /* Device management request data */ struct ufs_dev_cmd dev_cmd; From ab3dabb3e8cf077850f20610f73a0def1fed10cb Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 2 Jan 2017 11:04:58 -0300 Subject: [PATCH 0248/1587] scsi: ufs-qcom: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/scsi/ufs/ufs-qcom.ko | grep alias $ After this patch: $ modinfo drivers/scsi/ufs/ufs-qcom.ko | grep alias alias: of:N*T*Cqcom,ufshcC* alias: of:N*T*Cqcom,ufshc Signed-off-by: Javier Martinez Canillas Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index abe617372661..5ff8a6bf6fd3 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1692,6 +1692,7 @@ static const struct of_device_id ufs_qcom_of_match[] = { { .compatible = "qcom,ufshc"}, {}, }; +MODULE_DEVICE_TABLE(of, ufs_qcom_of_match); static const struct dev_pm_ops ufs_qcom_pm_ops = { .suspend = ufshcd_pltfrm_suspend, From d177c408113e5d8b664b2ae34e5cd7b27c686a12 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 3 Jan 2017 20:24:48 +0800 Subject: [PATCH 0249/1587] scsi: hisi_sas: service v2 hw CQ ISR with tasklet Currently the all the slot processing for the completion queue is done in ISR context. It is judged that the slot processing can take a long time, especially when a SATA NCQ completes (upto 32 slots). So, as a solution, defer the bulk of the ISR processing to tasklet context. Each CQ will have its down tasklet. Signed-off-by: John Garry Reviewed-by: Xiang Chen Reviewed-by: Zhangfei Gao Tested-by: Hanjun Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index c0cd505a9ef7..9216deaa3ff5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -95,6 +95,7 @@ struct hisi_sas_port { struct hisi_sas_cq { struct hisi_hba *hisi_hba; + struct tasklet_struct tasklet; int rd_point; int id; }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b934aec1eebb..e50626020b84 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2481,20 +2481,17 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) return IRQ_HANDLED; } -static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) +static void cq_tasklet_v2_hw(unsigned long val) { - struct hisi_sas_cq *cq = p; + struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val; struct hisi_hba *hisi_hba = cq->hisi_hba; struct hisi_sas_slot *slot; struct hisi_sas_itct *itct; struct hisi_sas_complete_v2_hdr *complete_queue; - u32 irq_value, rd_point = cq->rd_point, wr_point, dev_id; + u32 rd_point = cq->rd_point, wr_point, dev_id; int queue = cq->id; complete_queue = hisi_hba->complete_hdr[queue]; - irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); - - hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -2545,6 +2542,18 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); +} + +static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) +{ + struct hisi_sas_cq *cq = p; + struct hisi_hba *hisi_hba = cq->hisi_hba; + int queue = cq->id; + + hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); + + tasklet_schedule(&cq->tasklet); + return IRQ_HANDLED; } @@ -2726,6 +2735,8 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) for (i = 0; i < hisi_hba->queue_count; i++) { int idx = i + 96; /* First cq interrupt is irq96 */ + struct hisi_sas_cq *cq = &hisi_hba->cq[i]; + struct tasklet_struct *t = &cq->tasklet; irq = irq_map[idx]; if (!irq) { @@ -2742,6 +2753,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) irq, rc); return -ENOENT; } + tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq); } return 0; From 64d63187325884b96f684f1d839ec5d5ce231b92 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 3 Jan 2017 20:24:49 +0800 Subject: [PATCH 0250/1587] scsi: hisi_sas: lock sensitive regions when servicing CQ interrupt There is a bug in the current driver in that certain hisi_hba and port structure elements which we access when servicing the CQ interrupt do not use thread-safe accesses; these include hisi_sas_port linked-list of active slots (hisi_sas_port.entry), bitmap of currently allocated IPTT (in hisi_hba.slot_index_tags), and completion queue read pointer. As a solution, lock these elements with the hisi_hba.lock. Signed-off-by: John Garry Reviewed-by: Xiang Chen Reviewed-by: Zhangfei Gao Tested-by: Hanjun Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 2 ++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 8a1be0ba8a22..854fbeaade3e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1596,6 +1596,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) hisi_hba->complete_hdr[queue]; u32 irq_value, rd_point = cq->rd_point, wr_point; + spin_lock(&hisi_hba->lock); irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); @@ -1628,6 +1629,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); + spin_unlock(&hisi_hba->lock); return IRQ_HANDLED; } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index e50626020b84..69b0f06d1a96 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2493,6 +2493,7 @@ static void cq_tasklet_v2_hw(unsigned long val) complete_queue = hisi_hba->complete_hdr[queue]; + spin_lock(&hisi_hba->lock); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -2542,6 +2543,7 @@ static void cq_tasklet_v2_hw(unsigned long val) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); + spin_unlock(&hisi_hba->lock); } static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) From da7b66e720dcfb6754d6e3310a7ef315009b13db Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 3 Jan 2017 20:24:50 +0800 Subject: [PATCH 0251/1587] scsi: hisi_sas: lock sensitive region in hisi_sas_slot_abort() When we call hisi_sas_slot_task_free() we should grab the hisi_hba.lock, as hisi_sas_slot_task_free() accesses common hisi_hba elements. Function hisi_sas_slot_abort() is missing this, so add it. Signed-off-by: John Garry Reviewed-by: Zhangfei Gao Tested-by: Hanjun Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index d50e9cfefd24..22dba0143bdc 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -146,6 +146,7 @@ static void hisi_sas_slot_abort(struct work_struct *work) struct scsi_lun lun; struct device *dev = &hisi_hba->pdev->dev; int tag = abort_slot->idx; + unsigned long flags; if (!(task->task_proto & SAS_PROTOCOL_SSP)) { dev_err(dev, "cannot abort slot for non-ssp task\n"); @@ -159,7 +160,9 @@ static void hisi_sas_slot_abort(struct work_struct *work) hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task); out: /* Do cleanup for this task */ + spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_task_free(hisi_hba, task, abort_slot); + spin_unlock_irqrestore(&hisi_hba->lock, flags); if (task->task_done) task->task_done(task); if (sas_dev) From 352e5fd105982a9ea47d00c7256d6a2b7bb44d89 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 30 Dec 2016 06:57:47 -0800 Subject: [PATCH 0252/1587] scsi: lpfc: Reinstate lpfc_soft_wwn parameter The lpfc 11.2.0.4 patch set deprecated, by removing, the lpfc_soft_wwn parameter support. This patch reinstates support, but adds a warning in the enablement of the feature that indicates Broadcom (Emulex) does not support the feature. Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 4 + drivers/scsi/lpfc/lpfc_attr.c | 223 ++++++++++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_init.c | 16 ++- 3 files changed, 240 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index c2e6ffd2f372..6593b073c524 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -728,6 +728,8 @@ struct lpfc_hba { uint32_t cfg_total_seg_cnt; uint32_t cfg_sg_seg_cnt; uint32_t cfg_sg_dma_buf_size; + uint64_t cfg_soft_wwnn; + uint64_t cfg_soft_wwpn; uint32_t cfg_hba_queue_depth; uint32_t cfg_enable_hba_reset; uint32_t cfg_enable_hba_heartbeat; @@ -832,6 +834,8 @@ struct lpfc_hba { #define VPD_PORT 0x8 /* valid vpd port data */ #define VPD_MASK 0xf /* mask for any vpd data */ + uint8_t soft_wwn_enable; + struct timer_list fcp_poll_timer; struct timer_list eratt_poll; uint32_t eratt_poll_interval; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 8301c08b8768..6c104d79abe7 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1987,6 +1987,7 @@ static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show, NULL); +static char *lpfc_soft_wwn_key = "C99G71SL8032A"; #define WWN_SZ 8 /** * lpfc_wwn_set - Convert string to the 8 byte WWN value. @@ -2030,6 +2031,223 @@ lpfc_wwn_set(const char *buf, size_t cnt, char wwn[]) } return 0; } +/** + * lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: containing the string lpfc_soft_wwn_key. + * @count: must be size of lpfc_soft_wwn_key. + * + * Returns: + * -EINVAL if the buffer does not contain lpfc_soft_wwn_key + * length of buf indicates success + **/ +static ssize_t +lpfc_soft_wwn_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + unsigned int cnt = count; + + /* + * We're doing a simple sanity check for soft_wwpn setting. + * We require that the user write a specific key to enable + * the soft_wwpn attribute to be settable. Once the attribute + * is written, the enable key resets. If further updates are + * desired, the key must be written again to re-enable the + * attribute. + * + * The "key" is not secret - it is a hardcoded string shown + * here. The intent is to protect against the random user or + * application that is just writing attributes. + */ + + /* count may include a LF at end of string */ + if (buf[cnt-1] == '\n') + cnt--; + + if ((cnt != strlen(lpfc_soft_wwn_key)) || + (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0)) + return -EINVAL; + + phba->soft_wwn_enable = 1; + + dev_printk(KERN_WARNING, &phba->pcidev->dev, + "lpfc%d: soft_wwpn assignment has been enabled.\n", + phba->brd_no); + dev_printk(KERN_WARNING, &phba->pcidev->dev, + " The soft_wwpn feature is not supported by Broadcom."); + + return count; +} +static DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL, + lpfc_soft_wwn_enable_store); + +/** + * lpfc_soft_wwpn_show - Return the cfg soft ww port name of the adapter + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: on return contains the wwpn in hexadecimal. + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + return snprintf(buf, PAGE_SIZE, "0x%llx\n", + (unsigned long long)phba->cfg_soft_wwpn); +} + +/** + * lpfc_soft_wwpn_store - Set the ww port name of the adapter + * @dev class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: contains the wwpn in hexadecimal. + * @count: number of wwpn bytes in buf + * + * Returns: + * -EACCES hba reset not enabled, adapter over temp + * -EINVAL soft wwn not enabled, count is invalid, invalid wwpn byte invalid + * -EIO error taking adapter offline or online + * value of count on success + **/ +static ssize_t +lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct completion online_compl; + int stat1 = 0, stat2 = 0; + unsigned int cnt = count; + u8 wwpn[WWN_SZ]; + int rc; + + if (!phba->cfg_enable_hba_reset) + return -EACCES; + spin_lock_irq(&phba->hbalock); + if (phba->over_temp_state == HBA_OVER_TEMP) { + spin_unlock_irq(&phba->hbalock); + return -EACCES; + } + spin_unlock_irq(&phba->hbalock); + /* count may include a LF at end of string */ + if (buf[cnt-1] == '\n') + cnt--; + + if (!phba->soft_wwn_enable) + return -EINVAL; + + /* lock setting wwpn, wwnn down */ + phba->soft_wwn_enable = 0; + + rc = lpfc_wwn_set(buf, cnt, wwpn); + if (!rc) { + /* not able to set wwpn, unlock it */ + phba->soft_wwn_enable = 1; + return rc; + } + + phba->cfg_soft_wwpn = wwn_to_u64(wwpn); + fc_host_port_name(shost) = phba->cfg_soft_wwpn; + if (phba->cfg_soft_wwnn) + fc_host_node_name(shost) = phba->cfg_soft_wwnn; + + dev_printk(KERN_NOTICE, &phba->pcidev->dev, + "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no); + + stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); + if (stat1) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0463 lpfc_soft_wwpn attribute set failed to " + "reinit adapter - %d\n", stat1); + init_completion(&online_compl); + rc = lpfc_workq_post_event(phba, &stat2, &online_compl, + LPFC_EVT_ONLINE); + if (rc == 0) + return -ENOMEM; + + wait_for_completion(&online_compl); + if (stat2) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0464 lpfc_soft_wwpn attribute set failed to " + "reinit adapter - %d\n", stat2); + return (stat1 || stat2) ? -EIO : count; +} +static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR, + lpfc_soft_wwpn_show, lpfc_soft_wwpn_store); + +/** + * lpfc_soft_wwnn_show - Return the cfg soft ww node name for the adapter + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: on return contains the wwnn in hexadecimal. + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + return snprintf(buf, PAGE_SIZE, "0x%llx\n", + (unsigned long long)phba->cfg_soft_wwnn); +} + +/** + * lpfc_soft_wwnn_store - sets the ww node name of the adapter + * @cdev: class device that is converted into a Scsi_host. + * @buf: contains the ww node name in hexadecimal. + * @count: number of wwnn bytes in buf. + * + * Returns: + * -EINVAL soft wwn not enabled, count is invalid, invalid wwnn byte invalid + * value of count on success + **/ +static ssize_t +lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + unsigned int cnt = count; + u8 wwnn[WWN_SZ]; + int rc; + + /* count may include a LF at end of string */ + if (buf[cnt-1] == '\n') + cnt--; + + if (!phba->soft_wwn_enable) + return -EINVAL; + + rc = lpfc_wwn_set(buf, cnt, wwnn); + if (!rc) { + /* Allow wwnn to be set many times, as long as the enable + * is set. However, once the wwpn is set, everything locks. + */ + return rc; + } + + phba->cfg_soft_wwnn = wwn_to_u64(wwnn); + + dev_printk(KERN_NOTICE, &phba->pcidev->dev, + "lpfc%d: soft_wwnn set. Value will take effect upon " + "setting of the soft_wwpn\n", phba->brd_no); + + return count; +} +static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR, + lpfc_soft_wwnn_show, lpfc_soft_wwnn_store); /** * lpfc_oas_tgt_show - Return wwpn of target whose luns maybe enabled for @@ -4538,6 +4756,9 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_fcp_cpu_map, &dev_attr_lpfc_fcp_io_channel, &dev_attr_lpfc_enable_bg, + &dev_attr_lpfc_soft_wwnn, + &dev_attr_lpfc_soft_wwpn, + &dev_attr_lpfc_soft_wwn_enable, &dev_attr_lpfc_enable_hba_reset, &dev_attr_lpfc_enable_hba_heartbeat, &dev_attr_lpfc_EnableXLane, @@ -5566,6 +5787,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) else phba->cfg_poll = lpfc_poll; + phba->cfg_soft_wwnn = 0L; + phba->cfg_soft_wwpn = 0L; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 43d2b06bdc82..4776fd85514f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -319,26 +319,36 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) /** * lpfc_update_vport_wwn - Updates the fc_nodename, fc_portname, + * cfg_soft_wwnn, cfg_soft_wwpn * @vport: pointer to lpfc vport data structure. * + * * Return codes * None. **/ void lpfc_update_vport_wwn(struct lpfc_vport *vport) { + /* If the soft name exists then update it using the service params */ + if (vport->phba->cfg_soft_wwnn) + u64_to_wwn(vport->phba->cfg_soft_wwnn, + vport->fc_sparam.nodeName.u.wwn); + if (vport->phba->cfg_soft_wwpn) + u64_to_wwn(vport->phba->cfg_soft_wwpn, + vport->fc_sparam.portName.u.wwn); + /* - * If the name is empty + * If the name is empty or there exists a soft name * then copy the service params name, otherwise use the fc name */ - if (vport->fc_nodename.u.wwn[0] == 0) + if (vport->fc_nodename.u.wwn[0] == 0 || vport->phba->cfg_soft_wwnn) memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, sizeof(struct lpfc_name)); else memcpy(&vport->fc_sparam.nodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); - if (vport->fc_portname.u.wwn[0] == 0) + if (vport->fc_portname.u.wwn[0] == 0 || vport->phba->cfg_soft_wwpn) memcpy(&vport->fc_portname, &vport->fc_sparam.portName, sizeof(struct lpfc_name)); else From 62989cebd367a1aae1e009e1a5b1ec046a4c8fdc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 3 Jan 2017 19:09:44 +0100 Subject: [PATCH 0253/1587] ata: SATA_MV should depend on HAS_DMA If NO_DMA=y: ERROR: "dma_pool_alloc" [drivers/ata/sata_mv.ko] undefined! ERROR: "dmam_pool_create" [drivers/ata/sata_mv.ko] undefined! ERROR: "dma_pool_free" [drivers/ata/sata_mv.ko] undefined! Add a dependency on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 2c8be74f401d..842cd3450b57 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -353,6 +353,7 @@ config SATA_HIGHBANK config SATA_MV tristate "Marvell SATA support" + depends on HAS_DMA depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \ ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST select GENERIC_PHY From 2a736e0585e585c2566b5119af8381910a170e44 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 3 Jan 2017 19:09:45 +0100 Subject: [PATCH 0254/1587] ata: SATA_HIGHBANK should depend on HAS_DMA If NO_DMA=y: ERROR: "bad_dma_ops" [drivers/ata/sata_highbank.ko] undefined! Add a dependency on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 842cd3450b57..47d9356991e9 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -344,6 +344,7 @@ config SATA_DWC_VDEBUG config SATA_HIGHBANK tristate "Calxeda Highbank SATA support" + depends on HAS_DMA depends on ARCH_HIGHBANK || COMPILE_TEST help This option enables support for the Calxeda Highbank SoC's From 7bc7ab1e63dfe004931502f90ce7020e375623da Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 3 Jan 2017 19:09:46 +0100 Subject: [PATCH 0255/1587] ata: ATA_BMDMA should depend on HAS_DMA If NO_DMA=y: ERROR: "dmam_alloc_coherent" [drivers/ata/libata.ko] undefined! Add a dependency on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 47d9356991e9..5d16fc4fa46c 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -289,6 +289,7 @@ config SATA_SX4 config ATA_BMDMA bool "ATA BMDMA support" + depends on HAS_DMA default y help This option adds support for SFF ATA controllers with BMDMA From b16a0168c41f9379476b5b5585071319078c542d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 3 Jan 2017 19:09:47 +0100 Subject: [PATCH 0256/1587] ata: AHCI and other non-SFF native drivers should depend on HAS_DMA If NO_DMA=y: ERROR: "bad_dma_ops" [drivers/ata/libahci_platform.ko] undefined! ERROR: "dmam_alloc_coherent" [drivers/ata/libahci.ko] undefined! Add a block dependency on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 5d16fc4fa46c..38318aaf29d3 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -80,6 +80,8 @@ config SATA_PMP This option adds support for SATA Port Multipliers (the SATA version of an ethernet hub, or SAS expander). +if HAS_DMA + comment "Controllers with non-SFF native interface" config SATA_AHCI @@ -232,6 +234,8 @@ config SATA_SIL24 If unsure, say N. +endif # HAS_DMA + config ATA_SFF bool "ATA SFF support (for legacy IDE and PATA)" default y From 6cf32ed9eee2d34db441ba6ebad3ec2d67952688 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 3 Jan 2017 19:09:48 +0100 Subject: [PATCH 0257/1587] libata: Make ata_sg_clean() static again Commit 70e6ad0c6d1e6cb9 ("[PATCH] libata: prepare ata_sg_clean() for invocation from EH") made ata_sg_clean() global, but no user outside libata-core.c has ever materialized. Signed-off-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 2 +- drivers/ata/libata.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9cd0a2d41816..a7e3df5abaa3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4822,7 +4822,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, * LOCKING: * spin_lock_irqsave(host lock) */ -void ata_sg_clean(struct ata_queued_cmd *qc) +static void ata_sg_clean(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg = qc->sg; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 8f3a5596dd67..1133e9439f9c 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -89,7 +89,6 @@ extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); extern unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature); -extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); extern void __ata_qc_complete(struct ata_queued_cmd *qc); From 2874d5ee6c06ab72f2729968926b3d5ef8fca897 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 3 Jan 2017 19:09:49 +0100 Subject: [PATCH 0258/1587] libata: Protect DMA core code by #ifdef CONFIG_HAS_DMA If NO_DMA=y: ERROR: "bad_dma_ops" [drivers/ata/libata.ko] undefined! To fix this, protect the DMA code by #ifdef CONFIG_HAS_DMA, and provide dummies of ata_sg_clean() and ata_sg_setup() for the !CONFIG_HAS_DMA case. Signed-off-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 61 ++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a7e3df5abaa3..dc70b5f997f1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4813,32 +4813,6 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, return err_mask; } -/** - * ata_sg_clean - Unmap DMA memory associated with command - * @qc: Command containing DMA memory to be released - * - * Unmap all mapped DMA memory associated with this command. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -static void ata_sg_clean(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct scatterlist *sg = qc->sg; - int dir = qc->dma_dir; - - WARN_ON_ONCE(sg == NULL); - - VPRINTK("unmapping %u sg elements\n", qc->n_elem); - - if (qc->n_elem) - dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir); - - qc->flags &= ~ATA_QCFLAG_DMAMAP; - qc->sg = NULL; -} - /** * atapi_check_dma - Check whether ATAPI DMA can be supported * @qc: Metadata associated with taskfile to check @@ -4923,6 +4897,34 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, qc->cursg = qc->sg; } +#ifdef CONFIG_HAS_DMA + +/** + * ata_sg_clean - Unmap DMA memory associated with command + * @qc: Command containing DMA memory to be released + * + * Unmap all mapped DMA memory associated with this command. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_sg_clean(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg = qc->sg; + int dir = qc->dma_dir; + + WARN_ON_ONCE(sg == NULL); + + VPRINTK("unmapping %u sg elements\n", qc->n_elem); + + if (qc->n_elem) + dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir); + + qc->flags &= ~ATA_QCFLAG_DMAMAP; + qc->sg = NULL; +} + /** * ata_sg_setup - DMA-map the scatter-gather table associated with a command. * @qc: Command with scatter-gather table to be mapped. @@ -4955,6 +4957,13 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) return 0; } +#else /* !CONFIG_HAS_DMA */ + +static inline void ata_sg_clean(struct ata_queued_cmd *qc) {} +static inline int ata_sg_setup(struct ata_queued_cmd *qc) { return -1; } + +#endif /* !CONFIG_HAS_DMA */ + /** * swap_buf_le16 - swap halves of 16-bit words in place * @buf: Buffer to swap From de2518201e526f4491e5856b9818f5c18684a6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 5 Jan 2017 15:14:01 +0100 Subject: [PATCH 0259/1587] ata: ahci_xgene: free structure returned by acpi_get_object_info() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_get_object_info() allocates the returned structure, which the caller has to free when the call succeeds. Free it when appropriate. Fixes: c9802a4be661 ("ata: ahci_xgene: Add AHCI Support for 2nd HW version of APM X-Gene SoC AHCI SATA Host controller.") Signed-off-by: Michał Kępień Signed-off-by: Tejun Heo --- drivers/ata/ahci_xgene.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 73b19b277138..c2b5941d9184 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -821,8 +821,10 @@ static int xgene_ahci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n", __func__); version = XGENE_AHCI_V1; - } else if (info->valid & ACPI_VALID_CID) { - version = XGENE_AHCI_V2; + } else { + if (info->valid & ACPI_VALID_CID) + version = XGENE_AHCI_V2; + kfree(info); } } } From 66459c5a50a787c474b734b586328f7111ab6df0 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Fri, 6 Jan 2017 04:22:18 -0800 Subject: [PATCH 0260/1587] spi: imx: adjust watermark level according to transfer length Previously DMA watermark level is configured to fifosize/2, DMA mode can be used only when transfer length can be divided by 'watermark level * bpw', which makes DMA mode not pratical. This patch adjusts watermark level to largest number (no bigger than fifosize/2) which can divide 'tranfer length / bpw' for each transfer. Signed-off-by: Jiada Wang Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 32ced64a5bb9..9a7c62f471dc 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -211,7 +211,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - unsigned int bpw; + unsigned int bpw, i; if (!master->dma_rx) return false; @@ -228,11 +228,15 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, if (bpw != 1 && bpw != 2 && bpw != 4) return false; - if (transfer->len < spi_imx->wml * bpw) + for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) { + if (!(transfer->len % (i * bpw))) + break; + } + + if (i == 0) return false; - if (transfer->len % (spi_imx->wml * bpw)) - return false; + spi_imx->wml = i; return true; } @@ -837,10 +841,6 @@ static int spi_imx_dma_configure(struct spi_master *master, struct dma_slave_config rx = {}, tx = {}; struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - if (bytes_per_word == spi_imx->bytes_per_word) - /* Same as last time */ - return 0; - switch (bytes_per_word) { case 4: buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; From e360e72e715f228e426edf0fc99ffa34027ab0ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 29 Dec 2016 20:13:13 +0100 Subject: [PATCH 0261/1587] spi: bcm53xx: (re)license code to the GPL v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My intention was to release this code under GPL v2 license. For some reason my initial commit 0fc6a323e191 ("spi: bcm53xx: driver for SPI controller on Broadcom bcma SoC") totally missed licensing info. MODULE_LICENSE was later added by Axel specifying "GNU Public License v2 or later". This patch clarifies situation by adding a proper header (with Copyright line) and adjusting MODULE_LICENSE. It should be acked by every driver contributor. Signed-off-by: Rafał Miłecki Acked-by: Nicholas Mc Guire Reviewed-by: Jingoo Han Acked-by: Jingoo Han Acked-by: Joe Perches Acked-by: Axel Lin Acked-by: Vaishali Thakkar Signed-off-by: Mark Brown --- drivers/spi/spi-bcm53xx.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c index 0c61ad4edb1a..6e409eabe1c9 100644 --- a/drivers/spi/spi-bcm53xx.c +++ b/drivers/spi/spi-bcm53xx.c @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2014-2016 Rafał Miłecki + * + * 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. + */ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -355,4 +363,4 @@ module_exit(bcm53xxspi_module_exit); MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver"); MODULE_AUTHOR("Rafał Miłecki "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); From 54643a83b41a2bff90a0615799686b37a1109404 Mon Sep 17 00:00:00 2001 From: Csaba Kertesz Date: Tue, 25 Oct 2016 22:08:07 +0200 Subject: [PATCH 0262/1587] ahci: imx: Add imx53 SATA temperature sensor support Add a hwmon entry to get the temperature from the die of imx53 SATA. The original patch was made by Richard Zhu for kernel 2.6.x: ENGR00134041-MX53-Add-the-SATA-AHCI-temperature-monitor.patch Signed-off-by: Fabien Lahoudere Signed-off-by: Tejun Heo --- drivers/ata/ahci_imx.c | 195 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 3f3a7db208ae..420f065978dc 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include "ahci.h" #define DRV_NAME "ahci-imx" @@ -214,6 +217,180 @@ static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) return timeout ? 0 : -ETIMEDOUT; } +enum { + /* SATA PHY Register */ + SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT = 0x0001, + SATA_PHY_CR_CLOCK_DAC_CTL = 0x0008, + SATA_PHY_CR_CLOCK_RTUNE_CTL = 0x0009, + SATA_PHY_CR_CLOCK_ADC_OUT = 0x000A, + SATA_PHY_CR_CLOCK_MPLL_TST = 0x0017, +}; + +static int read_adc_sum(void *dev, u16 rtune_ctl_reg, void __iomem * mmio) +{ + u16 adc_out_reg, read_sum; + u32 index, read_attempt; + const u32 attempt_limit = 100; + + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio); + imx_phy_reg_write(rtune_ctl_reg, mmio); + + /* two dummy read */ + index = 0; + read_attempt = 0; + adc_out_reg = 0; + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_ADC_OUT, mmio); + while (index < 2) { + imx_phy_reg_read(&adc_out_reg, mmio); + /* check if valid */ + if (adc_out_reg & 0x400) + index++; + + read_attempt++; + if (read_attempt > attempt_limit) { + dev_err(dev, "Read REG more than %d times!\n", + attempt_limit); + break; + } + } + + index = 0; + read_attempt = 0; + read_sum = 0; + while (index < 80) { + imx_phy_reg_read(&adc_out_reg, mmio); + if (adc_out_reg & 0x400) { + read_sum = read_sum + (adc_out_reg & 0x3FF); + index++; + } + read_attempt++; + if (read_attempt > attempt_limit) { + dev_err(dev, "Read REG more than %d times!\n", + attempt_limit); + break; + } + } + + /* Use the U32 to make 1000 precision */ + return (read_sum * 1000) / 80; +} + +/* SATA AHCI temperature monitor */ +static int sata_ahci_read_temperature(void *dev, int *temp) +{ + u16 mpll_test_reg, rtune_ctl_reg, dac_ctl_reg, read_sum; + u32 str1, str2, str3, str4; + int m1, m2, a; + struct ahci_host_priv *hpriv = dev_get_drvdata(dev); + void __iomem *mmio = hpriv->mmio; + + /* check rd-wr to reg */ + read_sum = 0; + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT, mmio); + imx_phy_reg_write(read_sum, mmio); + imx_phy_reg_read(&read_sum, mmio); + if ((read_sum & 0xffff) != 0) + dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum); + + imx_phy_reg_write(0x5A5A, mmio); + imx_phy_reg_read(&read_sum, mmio); + if ((read_sum & 0xffff) != 0x5A5A) + dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum); + + imx_phy_reg_write(0x1234, mmio); + imx_phy_reg_read(&read_sum, mmio); + if ((read_sum & 0xffff) != 0x1234) + dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum); + + /* start temperature test */ + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio); + imx_phy_reg_read(&mpll_test_reg, mmio); + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio); + imx_phy_reg_read(&rtune_ctl_reg, mmio); + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio); + imx_phy_reg_read(&dac_ctl_reg, mmio); + + /* mpll_tst.meas_iv ([12:2]) */ + str1 = (mpll_test_reg >> 2) & 0x7FF; + /* rtune_ctl.mode ([1:0]) */ + str2 = (rtune_ctl_reg) & 0x3; + /* dac_ctl.dac_mode ([14:12]) */ + str3 = (dac_ctl_reg >> 12) & 0x7; + /* rtune_ctl.sel_atbp ([4]) */ + str4 = (rtune_ctl_reg >> 4); + + /* Calculate the m1 */ + /* mpll_tst.meas_iv */ + mpll_test_reg = (mpll_test_reg & 0xE03) | (512) << 2; + /* rtune_ctl.mode */ + rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (1); + /* dac_ctl.dac_mode */ + dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (4) << 12; + /* rtune_ctl.sel_atbp */ + rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (0) << 4; + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio); + imx_phy_reg_write(mpll_test_reg, mmio); + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio); + imx_phy_reg_write(dac_ctl_reg, mmio); + m1 = read_adc_sum(dev, rtune_ctl_reg, mmio); + + /* Calculate the m2 */ + /* rtune_ctl.sel_atbp */ + rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (1) << 4; + m2 = read_adc_sum(dev, rtune_ctl_reg, mmio); + + /* restore the status */ + /* mpll_tst.meas_iv */ + mpll_test_reg = (mpll_test_reg & 0xE03) | (str1) << 2; + /* rtune_ctl.mode */ + rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (str2); + /* dac_ctl.dac_mode */ + dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (str3) << 12; + /* rtune_ctl.sel_atbp */ + rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (str4) << 4; + + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio); + imx_phy_reg_write(mpll_test_reg, mmio); + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio); + imx_phy_reg_write(dac_ctl_reg, mmio); + imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio); + imx_phy_reg_write(rtune_ctl_reg, mmio); + + /* Compute temperature */ + if (!(m2 / 1000)) + m2 = 1000; + a = (m2 - m1) / (m2/1000); + *temp = ((-559) * a * a) / 1000 + (1379) * a + (-458000); + + return 0; +} + +static ssize_t sata_ahci_show_temp(struct device *dev, + struct device_attribute *da, + char *buf) +{ + unsigned int temp = 0; + int err; + + err = sata_ahci_read_temperature(dev, &temp); + if (err < 0) + return err; + + return sprintf(buf, "%u\n", temp); +} + +static const struct thermal_zone_of_device_ops fsl_sata_ahci_of_thermal_ops = { + .get_temp = sata_ahci_read_temperature, +}; + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sata_ahci_show_temp, NULL, 0); + +static struct attribute *fsl_sata_ahci_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(fsl_sata_ahci); + static int imx_sata_enable(struct ahci_host_priv *hpriv) { struct imx_ahci_priv *imxpriv = hpriv->plat_data; @@ -597,6 +774,24 @@ static int imx_ahci_probe(struct platform_device *pdev) if (ret) return ret; + if (imxpriv->type == AHCI_IMX53) { + /* Add the temperature monitor */ + struct device *hwmon_dev; + + hwmon_dev = + devm_hwmon_device_register_with_groups(dev, + "sata_ahci", + hpriv, + fsl_sata_ahci_groups); + if (IS_ERR(hwmon_dev)) { + ret = PTR_ERR(hwmon_dev); + goto disable_clk; + } + devm_thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev, + &fsl_sata_ahci_of_thermal_ops); + dev_info(dev, "%s: sensor 'sata_ahci'\n", dev_name(hwmon_dev)); + } + ret = imx_sata_enable(hpriv); if (ret) goto disable_clk; From 88af4bbd8f6983378c3098ca3e26c4e48434fe69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 20 Dec 2016 22:15:22 +0100 Subject: [PATCH 0263/1587] ata: sata_mv: fix module license specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header allows GPL v2 only, so declare "GPL v2" for MODULE_LICENSE Signed-off-by: Uwe Kleine-König Signed-off-by: Tejun Heo --- drivers/ata/sata_mv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 823e938c9a78..bcbfe23a45f6 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4526,7 +4526,7 @@ static void __exit mv_exit(void) MODULE_AUTHOR("Brett Russ"); MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DEVICE_TABLE(pci, mv_pci_tbl); MODULE_VERSION(DRV_VERSION); MODULE_ALIAS("platform:" DRV_NAME); From b63f5e84826b3e1ae81e051a6a7c5a94b657aecb Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Fri, 6 Jan 2017 22:14:28 -0500 Subject: [PATCH 0264/1587] GFS2: Wake up io waiters whenever a flush is done Before this patch, if a process called function gfs2_log_reserve to reserve some journal blocks, but the journal not enough blocks were free, it would call io_schedule. However, in the log flush daemon, it woke up the waiters only if an gfs2_ail_flush was no longer required. This resulted in situations where processes would wait forever because the number of blocks required was so high that it pushed the journal into a perpetual state of flush being required. This patch changes the logd daemon so that it wakes up io waiters every time the log is actually flushed. Signed-off-by: Bob Peterson --- fs/gfs2/log.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 4df349c7f022..5028a9d00c17 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -918,12 +918,15 @@ int gfs2_logd(void *data) struct gfs2_sbd *sdp = data; unsigned long t = 1; DEFINE_WAIT(wait); + bool did_flush; while (!kthread_should_stop()) { + did_flush = false; if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { gfs2_ail1_empty(sdp); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); + did_flush = true; } if (gfs2_ail_flush_reqd(sdp)) { @@ -931,9 +934,10 @@ int gfs2_logd(void *data) gfs2_ail1_wait(sdp); gfs2_ail1_empty(sdp); gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); + did_flush = true; } - if (!gfs2_ail_flush_reqd(sdp)) + if (!gfs2_ail_flush_reqd(sdp) || did_flush) wake_up(&sdp->sd_log_waitq); t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; From 173b8439e1ba362007315868928bf9d26e5cc5a6 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 28 Dec 2016 00:22:52 -0500 Subject: [PATCH 0265/1587] ext4: don't allow encrypted operations without keys While we allow deletes without the key, the following should not be permitted: # cd /vdc/encrypted-dir-without-key # ls -l total 4 -rw-r--r-- 1 root root 0 Dec 27 22:35 6,LKNRJsp209FbXoSvJWzB -rw-r--r-- 1 root root 286 Dec 27 22:35 uRJ5vJh9gE7vcomYMqTAyD # mv uRJ5vJh9gE7vcomYMqTAyD 6,LKNRJsp209FbXoSvJWzB Signed-off-by: Theodore Ts'o --- fs/ext4/namei.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 80b8afa4a8f9..bb880c326191 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3527,6 +3527,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, EXT4_I(old_dentry->d_inode)->i_projid))) return -EXDEV; + if ((ext4_encrypted_inode(old_dir) && + !fscrypt_has_encryption_key(old_dir)) || + (ext4_encrypted_inode(new_dir) && + !fscrypt_has_encryption_key(new_dir))) + return -ENOKEY; + retval = dquot_initialize(old.dir); if (retval) return retval; @@ -3727,6 +3733,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, int retval; struct timespec ctime; + if ((ext4_encrypted_inode(old_dir) && + !fscrypt_has_encryption_key(old_dir)) || + (ext4_encrypted_inode(new_dir) && + !fscrypt_has_encryption_key(new_dir))) + return -ENOKEY; + if ((ext4_encrypted_inode(old_dir) || ext4_encrypted_inode(new_dir)) && (old_dir != new_dir) && From f099d616dd689d27b08dec95d0b6f1f302cf8ec4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 5 Jan 2017 12:01:30 -0800 Subject: [PATCH 0266/1587] fscrypt: remove unused 'mode' member of fscrypt_ctx Nothing reads or writes fscrypt_ctx.mode, and it doesn't belong there because a fscrypt_ctx is not tied to a specific encryption mode. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- include/linux/fscrypto.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index 2a2815702095..8635ea46ef6e 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -35,7 +35,6 @@ struct fscrypt_ctx { struct list_head free_list; /* Free list */ }; u8 flags; /* Flags */ - u8 mode; /* Encryption mode for tfm */ }; /** From a5d431eff2e0bb22156897435aa277ddc96074f7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 5 Jan 2017 13:51:18 -0800 Subject: [PATCH 0267/1587] fscrypt: make fscrypt_operations.key_prefix a string There was an unnecessary amount of complexity around requesting the filesystem-specific key prefix. It was unclear why; perhaps it was envisioned that different instances of the same filesystem type could use different key prefixes, or that key prefixes could be binary. However, neither of those things were implemented or really make sense at all. So simplify the code by making key_prefix a const char *. Signed-off-by: Eric Biggers Reviewed-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/keyinfo.c | 31 +++++++++++-------------------- fs/ext4/ext4.h | 11 ----------- fs/ext4/super.c | 13 +------------ fs/f2fs/f2fs.h | 9 --------- fs/f2fs/super.c | 14 +------------- fs/ubifs/crypto.c | 11 +---------- include/linux/fscrypto.h | 2 +- 7 files changed, 15 insertions(+), 76 deletions(-) diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 80f145c8d550..eeb6fd67ea17 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -77,26 +77,22 @@ out: static int validate_user_key(struct fscrypt_info *crypt_info, struct fscrypt_context *ctx, u8 *raw_key, - u8 *prefix, int prefix_size) + const char *prefix) { - u8 *full_key_descriptor; + char *description; struct key *keyring_key; struct fscrypt_key *master_key; const struct user_key_payload *ukp; - int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1; int res; - full_key_descriptor = kmalloc(full_key_len, GFP_NOFS); - if (!full_key_descriptor) + description = kasprintf(GFP_NOFS, "%s%*phN", prefix, + FS_KEY_DESCRIPTOR_SIZE, + ctx->master_key_descriptor); + if (!description) return -ENOMEM; - memcpy(full_key_descriptor, prefix, prefix_size); - sprintf(full_key_descriptor + prefix_size, - "%*phN", FS_KEY_DESCRIPTOR_SIZE, - ctx->master_key_descriptor); - full_key_descriptor[full_key_len - 1] = '\0'; - keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL); - kfree(full_key_descriptor); + keyring_key = request_key(&key_type_logon, description, NULL); + kfree(description); if (IS_ERR(keyring_key)) return PTR_ERR(keyring_key); @@ -251,15 +247,10 @@ retry: if (!raw_key) goto out; - res = validate_user_key(crypt_info, &ctx, raw_key, - FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE); + res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX); if (res && inode->i_sb->s_cop->key_prefix) { - u8 *prefix = NULL; - int prefix_size, res2; - - prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix); - res2 = validate_user_key(crypt_info, &ctx, raw_key, - prefix, prefix_size); + int res2 = validate_user_key(crypt_info, &ctx, raw_key, + inode->i_sb->s_cop->key_prefix); if (res2) { if (res2 == -ENOKEY) res = -ENOKEY; diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 2163c1e69f2a..6bcb9622fdf9 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1343,11 +1343,6 @@ struct ext4_super_block { /* Number of quota types we support */ #define EXT4_MAXQUOTAS 3 -#ifdef CONFIG_EXT4_FS_ENCRYPTION -#define EXT4_KEY_DESC_PREFIX "ext4:" -#define EXT4_KEY_DESC_PREFIX_SIZE 5 -#endif - /* * fourth extended-fs super-block data in memory */ @@ -1517,12 +1512,6 @@ struct ext4_sb_info { /* Barrier between changing inodes' journal flags and writepages ops. */ struct percpu_rw_semaphore s_journal_flag_rwsem; - - /* Encryption support */ -#ifdef CONFIG_EXT4_FS_ENCRYPTION - u8 key_prefix[EXT4_KEY_DESC_PREFIX_SIZE]; - u8 key_prefix_size; -#endif }; static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 66845a08a87a..9d15a6293124 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1100,12 +1100,6 @@ static int ext4_get_context(struct inode *inode, void *ctx, size_t len) EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len); } -static int ext4_key_prefix(struct inode *inode, u8 **key) -{ - *key = EXT4_SB(inode->i_sb)->key_prefix; - return EXT4_SB(inode->i_sb)->key_prefix_size; -} - static int ext4_prepare_context(struct inode *inode) { return ext4_convert_inline_data(inode); @@ -1180,8 +1174,8 @@ static unsigned ext4_max_namelen(struct inode *inode) } static struct fscrypt_operations ext4_cryptops = { + .key_prefix = "ext4:", .get_context = ext4_get_context, - .key_prefix = ext4_key_prefix, .prepare_context = ext4_prepare_context, .set_context = ext4_set_context, .dummy_context = ext4_dummy_context, @@ -4218,11 +4212,6 @@ no_journal: ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10); kfree(orig_data); -#ifdef CONFIG_EXT4_FS_ENCRYPTION - memcpy(sbi->key_prefix, EXT4_KEY_DESC_PREFIX, - EXT4_KEY_DESC_PREFIX_SIZE); - sbi->key_prefix_size = EXT4_KEY_DESC_PREFIX_SIZE; -#endif return 0; cantfind_ext4: diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 2da8c3aa0ce5..93d38d854a41 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -760,10 +760,6 @@ enum { MAX_TIME, }; -#ifdef CONFIG_F2FS_FS_ENCRYPTION -#define F2FS_KEY_DESC_PREFIX "f2fs:" -#define F2FS_KEY_DESC_PREFIX_SIZE 5 -#endif struct f2fs_sb_info { struct super_block *sb; /* pointer to VFS super block */ struct proc_dir_entry *s_proc; /* proc entry */ @@ -771,11 +767,6 @@ struct f2fs_sb_info { int valid_super_block; /* valid super block no */ unsigned long s_flag; /* flags for sbi */ -#ifdef CONFIG_F2FS_FS_ENCRYPTION - u8 key_prefix[F2FS_KEY_DESC_PREFIX_SIZE]; - u8 key_prefix_size; -#endif - #ifdef CONFIG_BLK_DEV_ZONED unsigned int blocks_per_blkz; /* F2FS blocks per zone */ unsigned int log_blocks_per_blkz; /* log2 F2FS blocks per zone */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 702638e21c76..739192d95e71 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1156,12 +1156,6 @@ static int f2fs_get_context(struct inode *inode, void *ctx, size_t len) ctx, len, NULL); } -static int f2fs_key_prefix(struct inode *inode, u8 **key) -{ - *key = F2FS_I_SB(inode)->key_prefix; - return F2FS_I_SB(inode)->key_prefix_size; -} - static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len, void *fs_data) { @@ -1177,8 +1171,8 @@ static unsigned f2fs_max_namelen(struct inode *inode) } static struct fscrypt_operations f2fs_cryptops = { + .key_prefix = "f2fs:", .get_context = f2fs_get_context, - .key_prefix = f2fs_key_prefix, .set_context = f2fs_set_context, .is_encrypted = f2fs_encrypted_inode, .empty_dir = f2fs_empty_dir, @@ -1518,12 +1512,6 @@ static void init_sb_info(struct f2fs_sb_info *sbi) mutex_init(&sbi->wio_mutex[NODE]); mutex_init(&sbi->wio_mutex[DATA]); spin_lock_init(&sbi->cp_lock); - -#ifdef CONFIG_F2FS_FS_ENCRYPTION - memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX, - F2FS_KEY_DESC_PREFIX_SIZE); - sbi->key_prefix_size = F2FS_KEY_DESC_PREFIX_SIZE; -#endif } static int init_percpu_info(struct f2fs_sb_info *sbi) diff --git a/fs/ubifs/crypto.c b/fs/ubifs/crypto.c index 3402720f2b28..6335abcf98df 100644 --- a/fs/ubifs/crypto.c +++ b/fs/ubifs/crypto.c @@ -26,15 +26,6 @@ static unsigned int ubifs_crypt_max_namelen(struct inode *inode) return UBIFS_MAX_NLEN; } -static int ubifs_key_prefix(struct inode *inode, u8 **key) -{ - static char prefix[] = "ubifs:"; - - *key = prefix; - - return sizeof(prefix) - 1; -} - int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn, unsigned int in_len, unsigned int *out_len, int block) { @@ -88,10 +79,10 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn, struct fscrypt_operations ubifs_crypt_operations = { .flags = FS_CFLG_OWN_PAGES, + .key_prefix = "ubifs:", .get_context = ubifs_crypt_get_context, .set_context = ubifs_crypt_set_context, .is_encrypted = __ubifs_crypt_is_encrypted, .empty_dir = ubifs_crypt_empty_dir, .max_namelen = ubifs_crypt_max_namelen, - .key_prefix = ubifs_key_prefix, }; diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index 8635ea46ef6e..715f17b3c6d7 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -85,8 +85,8 @@ struct fscrypt_name { */ struct fscrypt_operations { unsigned int flags; + const char *key_prefix; int (*get_context)(struct inode *, void *, size_t); - int (*key_prefix)(struct inode *, u8 **); int (*prepare_context)(struct inode *); int (*set_context)(struct inode *, const void *, size_t, void *); int (*dummy_context)(struct inode *); From 2a9b8cba62c0741109c33a2be700ff3d7703a7c2 Mon Sep 17 00:00:00 2001 From: Roman Pen Date: Sun, 8 Jan 2017 20:59:35 -0500 Subject: [PATCH 0268/1587] ext4: Include forgotten start block on fallocate insert range While doing 'insert range' start block should be also shifted right. The bug can be easily reproduced by the following test: ptr = malloc(4096); assert(ptr); fd = open("./ext4.file", O_CREAT | O_TRUNC | O_RDWR, 0600); assert(fd >= 0); rc = fallocate(fd, 0, 0, 8192); assert(rc == 0); for (i = 0; i < 2048; i++) *((unsigned short *)ptr + i) = 0xbeef; rc = pwrite(fd, ptr, 4096, 0); assert(rc == 4096); rc = pwrite(fd, ptr, 4096, 4096); assert(rc == 4096); for (block = 2; block < 1000; block++) { rc = fallocate(fd, FALLOC_FL_INSERT_RANGE, 4096, 4096); assert(rc == 0); for (i = 0; i < 2048; i++) *((unsigned short *)ptr + i) = block; rc = pwrite(fd, ptr, 4096, 4096); assert(rc == 4096); } Because start block is not included in the range the hole appears at the wrong offset (just after the desired offset) and the following pwrite() overwrites already existent block, keeping hole untouched. Simple way to verify wrong behaviour is to check zeroed blocks after the test: $ hexdump ./ext4.file | grep '0000 0000' The root cause of the bug is a wrong range (start, stop], where start should be inclusive, i.e. [start, stop]. This patch fixes the problem by including start into the range. But not to break left shift (range collapse) stop points to the beginning of the a block, not to the end. The other not obvious change is an iterator check on validness in a main loop. Because iterator is unsigned the following corner case should be considered with care: insert a block at 0 offset, when stop variables overflows and never becomes less than start, which is 0. To handle this special case iterator is set to NULL to indicate that end of the loop is reached. Fixes: 331573febb6a2 Signed-off-by: Roman Pen Signed-off-by: Theodore Ts'o Cc: Namjae Jeon Cc: Andreas Dilger Cc: stable@vger.kernel.org --- fs/ext4/extents.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 3e295d3350a9..4d3014b5a3f9 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -5343,8 +5343,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, if (!extent) goto out; - stop = le32_to_cpu(extent->ee_block) + - ext4_ext_get_actual_len(extent); + stop = le32_to_cpu(extent->ee_block); /* * In case of left shift, Don't start shifting extents until we make @@ -5383,8 +5382,12 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, else iterator = &stop; - /* Its safe to start updating extents */ - while (start < stop) { + /* + * Its safe to start updating extents. Start and stop are unsigned, so + * in case of right shift if extent with 0 block is reached, iterator + * becomes NULL to indicate the end of the loop. + */ + while (iterator && start <= stop) { path = ext4_find_extent(inode, *iterator, &path, 0); if (IS_ERR(path)) return PTR_ERR(path); @@ -5412,8 +5415,11 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, ext4_ext_get_actual_len(extent); } else { extent = EXT_FIRST_EXTENT(path[depth].p_hdr); - *iterator = le32_to_cpu(extent->ee_block) > 0 ? - le32_to_cpu(extent->ee_block) - 1 : 0; + if (le32_to_cpu(extent->ee_block) > 0) + *iterator = le32_to_cpu(extent->ee_block) - 1; + else + /* Beginning is reached, end of the loop */ + iterator = NULL; /* Update path extent in case we need to stop */ while (le32_to_cpu(extent->ee_block) < start) extent++; From 03e916fa8b5577d85471452a3d0c5738aa658dae Mon Sep 17 00:00:00 2001 From: Roman Pen Date: Sun, 8 Jan 2017 21:00:35 -0500 Subject: [PATCH 0269/1587] ext4: do not polute the extents cache while shifting extents Inside ext4_ext_shift_extents() function ext4_find_extent() is called without EXT4_EX_NOCACHE flag, which should prevent cache population. This leads to oudated offsets in the extents tree and wrong blocks afterwards. Patch fixes the problem providing EXT4_EX_NOCACHE flag for each ext4_find_extents() call inside ext4_ext_shift_extents function. Fixes: 331573febb6a2 Signed-off-by: Roman Pen Signed-off-by: Theodore Ts'o Cc: Namjae Jeon Cc: Andreas Dilger Cc: stable@vger.kernel.org --- fs/ext4/extents.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 4d3014b5a3f9..2a97dff87b96 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -5334,7 +5334,8 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, ext4_lblk_t stop, *iterator, ex_start, ex_end; /* Let path point to the last extent */ - path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0); + path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, + EXT4_EX_NOCACHE); if (IS_ERR(path)) return PTR_ERR(path); @@ -5350,7 +5351,8 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, * sure the hole is big enough to accommodate the shift. */ if (SHIFT == SHIFT_LEFT) { - path = ext4_find_extent(inode, start - 1, &path, 0); + path = ext4_find_extent(inode, start - 1, &path, + EXT4_EX_NOCACHE); if (IS_ERR(path)) return PTR_ERR(path); depth = path->p_depth; @@ -5388,7 +5390,8 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, * becomes NULL to indicate the end of the loop. */ while (iterator && start <= stop) { - path = ext4_find_extent(inode, *iterator, &path, 0); + path = ext4_find_extent(inode, *iterator, &path, + EXT4_EX_NOCACHE); if (IS_ERR(path)) return PTR_ERR(path); depth = path->p_depth; From 916cafdc95843fb9af5fd5f83ca499d75473d107 Mon Sep 17 00:00:00 2001 From: Mathias Svensson Date: Fri, 6 Jan 2017 13:32:39 -0800 Subject: [PATCH 0270/1587] samples/seccomp: fix 64-bit comparison macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There were some bugs in the JNE64 and JLT64 comparision macros. This fixes them, improves comments, and cleans up the file while we are at it. Reported-by: Stephen Röttger Signed-off-by: Mathias Svensson Signed-off-by: Kees Cook Cc: stable@vger.kernel.org Signed-off-by: James Morris --- samples/seccomp/bpf-helper.h | 139 ++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 60 deletions(-) diff --git a/samples/seccomp/bpf-helper.h b/samples/seccomp/bpf-helper.h index 38ee70f3cd5b..1d8de9edd858 100644 --- a/samples/seccomp/bpf-helper.h +++ b/samples/seccomp/bpf-helper.h @@ -138,7 +138,7 @@ union arg64 { #define ARG_32(idx) \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)) -/* Loads hi into A and lo in X */ +/* Loads lo into M[0] and hi into M[1] and A */ #define ARG_64(idx) \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \ BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \ @@ -153,62 +153,14 @@ union arg64 { BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \ jt -/* Checks the lo, then swaps to check the hi. A=lo,X=hi */ -#define JEQ64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ - jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ - -#define JNE64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 5, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ - jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ - #define JA32(value, jt) \ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \ jt -#define JA64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ - BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ - jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ - #define JGE32(value, jt) \ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \ jt -#define JLT32(value, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \ - jt - -/* Shortcut checking if hi > arg.hi. */ -#define JGE64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ - BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ - jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ - -#define JLT64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ - jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ - #define JGT32(value, jt) \ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \ jt @@ -217,24 +169,91 @@ union arg64 { BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \ jt -/* Check hi > args.hi first, then do the GE checking */ -#define JGT64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ +#define JLT32(value, jt) \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \ + jt + +/* + * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both + * A and M[1]. This invariant is kept by restoring A if necessary. + */ +#define JEQ64(lo, hi, jt) \ + /* if (hi != arg.hi) goto NOMATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ + /* if (lo != arg.lo) goto NOMATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ + BPF_STMT(BPF_LD+BPF_MEM, 1) + +#define JNE64(lo, hi, jt) \ + /* if (hi != arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo != arg.lo) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ + jt, \ + BPF_STMT(BPF_LD+BPF_MEM, 1) + +#define JA64(lo, hi, jt) \ + /* if (hi & arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo & arg.lo) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ + jt, \ + BPF_STMT(BPF_LD+BPF_MEM, 1) + +#define JGE64(lo, hi, jt) \ + /* if (hi > arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ + /* if (hi != arg.hi) goto NOMATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo >= arg.lo) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ + jt, \ + BPF_STMT(BPF_LD+BPF_MEM, 1) + +#define JGT64(lo, hi, jt) \ + /* if (hi > arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ + /* if (hi != arg.hi) goto NOMATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo > arg.lo) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ + jt, \ + BPF_STMT(BPF_LD+BPF_MEM, 1) #define JLE64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 6, 0), \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ + /* if (hi < arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ + /* if (hi != arg.hi) goto NOMATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo <= arg.lo) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ + BPF_STMT(BPF_LD+BPF_MEM, 1) + +#define JLT64(lo, hi, jt) \ + /* if (hi < arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ + /* if (hi != arg.hi) goto NOMATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo < arg.lo) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ + jt, \ + BPF_STMT(BPF_LD+BPF_MEM, 1) #define LOAD_SYSCALL_NR \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ From e70002c80d4de20a5c61c16ecd4f40a48be3efcf Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Fri, 6 Jan 2017 17:35:13 +0800 Subject: [PATCH 0271/1587] spi: dw: Make debugfs use bus num and make irq name unique Instead of using device name it was suggested that bus number was more appropriate to differentiate debugfs names. Also reduce buffer size to more realistic 32 bytes instead of 128. When request_irq is called the bus number may not be assigned. Therefore the irq name was not unique when dynamic bus number was being used. As per most of the spi drivers use the device name instead. No other use of dws->name could be found so it was removed. Signed-off-by: Phil Reid Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 8 ++++---- drivers/spi/spi-dw.h | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 054012f87567..b217c22ff72f 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -107,9 +107,9 @@ static const struct file_operations dw_spi_regs_ops = { static int dw_spi_debugfs_init(struct dw_spi *dws) { - char name[128]; + char name[32]; - snprintf(name, 128, "dw_spi-%s", dev_name(&dws->master->dev)); + snprintf(name, 32, "dw_spi%d", dws->master->bus_num); dws->debugfs = debugfs_create_dir(name, NULL); if (!dws->debugfs) return -ENOMEM; @@ -486,9 +486,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->type = SSI_MOTO_SPI; dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); - snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num); - ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master); + ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), + master); if (ret < 0) { dev_err(dev, "can not get IRQ\n"); goto err_free_master; diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index c21ca02f8ec5..da5eab62df34 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -101,7 +101,6 @@ struct dw_spi_dma_ops { struct dw_spi { struct spi_master *master; enum dw_ssi_type type; - char name[16]; void __iomem *regs; unsigned long paddr; From 3d63a47a380a873408dad10ca62bd8299b2208f1 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 9 Jan 2017 11:36:10 +0100 Subject: [PATCH 0272/1587] spi: s3c64xx: Don't request/release DMA channels for each SPI transfer Requesting a DMA channel might be a time consuming operation, so there is no need to acquire and release DMA channel for each SPI transfer. DMA channels can be requested during driver probe and kept all the time, also because there are no shared nor dynamically allocated channels on Samsung S3C/S5P/Exynos platforms. While moving dma_requrest_slave_channel calls, lets switch to dma_request_slave_channel_reason(), which returns error codes on failure, which can be properly propagated to the caller (this for example defers SPI probe when DMA controller is not yet available). Signed-off-by: Marek Szyprowski Reviewed-by: Andi Shyti Tested-by: Andi Shyti Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 57 ++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 28dfdce4beae..849ee82483e4 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -341,43 +341,16 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable) static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) { struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - struct device *dev = &sdd->pdev->dev; if (is_polling(sdd)) return 0; - /* Acquire DMA channels */ - sdd->rx_dma.ch = dma_request_slave_channel(dev, "rx"); - if (!sdd->rx_dma.ch) { - dev_err(dev, "Failed to get RX DMA channel\n"); - return -EBUSY; - } spi->dma_rx = sdd->rx_dma.ch; - - sdd->tx_dma.ch = dma_request_slave_channel(dev, "tx"); - if (!sdd->tx_dma.ch) { - dev_err(dev, "Failed to get TX DMA channel\n"); - dma_release_channel(sdd->rx_dma.ch); - return -EBUSY; - } spi->dma_tx = sdd->tx_dma.ch; return 0; } -static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* Free DMA channels */ - if (!is_polling(sdd)) { - dma_release_channel(sdd->rx_dma.ch); - dma_release_channel(sdd->tx_dma.ch); - } - - return 0; -} - static bool s3c64xx_spi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) @@ -1094,7 +1067,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; master->prepare_message = s3c64xx_spi_prepare_message; master->transfer_one = s3c64xx_spi_transfer_one; - master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->num_chipselect = sci->num_cs; master->dma_alignment = 8; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | @@ -1161,6 +1133,24 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) } } + if (!is_polling(sdd)) { + /* Acquire DMA channels */ + sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, + "rx"); + if (IS_ERR(sdd->rx_dma.ch)) { + dev_err(&pdev->dev, "Failed to get RX DMA channel\n"); + ret = PTR_ERR(sdd->rx_dma.ch); + goto err_disable_io_clk; + } + sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, + "tx"); + if (IS_ERR(sdd->tx_dma.ch)) { + dev_err(&pdev->dev, "Failed to get TX DMA channel\n"); + ret = PTR_ERR(sdd->tx_dma.ch); + goto err_release_tx_dma; + } + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -1206,6 +1196,12 @@ err_pm_put: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); + if (!is_polling(sdd)) + dma_release_channel(sdd->rx_dma.ch); +err_release_tx_dma: + if (!is_polling(sdd)) + dma_release_channel(sdd->tx_dma.ch); +err_disable_io_clk: clk_disable_unprepare(sdd->ioclk); err_disable_src_clk: clk_disable_unprepare(sdd->src_clk); @@ -1226,6 +1222,11 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) writel(0, sdd->regs + S3C64XX_SPI_INT_EN); + if (!is_polling(sdd)) { + dma_release_channel(sdd->rx_dma.ch); + dma_release_channel(sdd->tx_dma.ch); + } + clk_disable_unprepare(sdd->ioclk); clk_disable_unprepare(sdd->src_clk); From 368e5fbdfc60732643f34f538823ed4bc8829827 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 9 Jan 2017 00:49:22 +0200 Subject: [PATCH 0273/1587] ata: sata_mv: Convert to devm_ioremap_resource() Convert to devm_ioremap_resource() which provides more consistent error handling. Note that devm_ioremap_resource() provides its own error messages. Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo --- drivers/ata/sata_mv.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 6eed4a72d328..00ce26d0c047 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4067,6 +4067,7 @@ static int mv_platform_probe(struct platform_device *pdev) struct ata_host *host; struct mv_host_priv *hpriv; struct resource *res; + void __iomem *mmio; int n_ports = 0, irq = 0; int rc; int port; @@ -4085,8 +4086,9 @@ static int mv_platform_probe(struct platform_device *pdev) * Get the register base first */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) - return -EINVAL; + mmio = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mmio)) + return PTR_ERR(mmio); /* allocate host */ if (pdev->dev.of_node) { @@ -4130,12 +4132,7 @@ static int mv_platform_probe(struct platform_device *pdev) hpriv->board_idx = chip_soc; host->iomap = NULL; - hpriv->base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!hpriv->base) - return -ENOMEM; - - hpriv->base -= SATAHC0_REG_BASE; + hpriv->base = mmio - SATAHC0_REG_BASE; hpriv->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(hpriv->clk)) From 578db85f6777efedfc5b47a34f5b6576caa29eac Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sun, 8 Jan 2017 22:31:15 +0100 Subject: [PATCH 0274/1587] pinctrl: sunxi: Add pinctrl variants Some SoCs are either supposed to be pin compatible (A10 and A20 for example), or are just repackaged versions of the same die (A10s, A13, GR8). In those case, having a full blown pinctrl driver just introduces duplication in both data size and maintainance effort. Add a variant option to both pins and functions to be able to limit the pins and functions described only to a subset of the SoC we support with a given driver. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 77 ++++++++++++++++++++------- drivers/pinctrl/sunxi/pinctrl-sunxi.h | 26 ++++++++- 2 files changed, 81 insertions(+), 22 deletions(-) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 0eb51e33cb1b..a69f7588e078 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -1041,21 +1041,35 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev); int i; - pctl->ngroups = pctl->desc->npins; + /* + * Allocate groups + * + * We assume that the number of groups is the number of pins + * given in the data array. - /* Allocate groups */ + * This will not always be true, since some pins might not be + * available in the current variant, but fortunately for us, + * this means that the number of pins is the maximum group + * number we will ever see. + */ pctl->groups = devm_kzalloc(&pdev->dev, - pctl->ngroups * sizeof(*pctl->groups), + pctl->desc->npins * sizeof(*pctl->groups), GFP_KERNEL); if (!pctl->groups) return -ENOMEM; for (i = 0; i < pctl->desc->npins; i++) { const struct sunxi_desc_pin *pin = pctl->desc->pins + i; - struct sunxi_pinctrl_group *group = pctl->groups + i; + struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups; + + if (pin->variant && !(pctl->variant & pin->variant)) + continue; group->name = pin->pin.name; group->pin = pin->pin.number; + + /* And now we count the actual number of pins / groups */ + pctl->ngroups++; } /* @@ -1063,17 +1077,23 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) * we'll reallocate that later anyway */ pctl->functions = devm_kzalloc(&pdev->dev, - pctl->desc->npins * sizeof(*pctl->functions), - GFP_KERNEL); + pctl->ngroups * sizeof(*pctl->functions), + GFP_KERNEL); if (!pctl->functions) return -ENOMEM; /* Count functions and their associated groups */ for (i = 0; i < pctl->desc->npins; i++) { const struct sunxi_desc_pin *pin = pctl->desc->pins + i; - struct sunxi_desc_function *func = pin->functions; + struct sunxi_desc_function *func; + + if (pin->variant && !(pctl->variant & pin->variant)) + continue; + + for (func = pin->functions; func->name; func++) { + if (func->variant && !(pctl->variant & func->variant)) + continue; - while (func->name) { /* Create interrupt mapping while we're at it */ if (!strcmp(func->name, "irq")) { int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK; @@ -1081,22 +1101,32 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) } sunxi_pinctrl_add_function(pctl, func->name); - func++; } } + /* And now allocated and fill the array for real */ pctl->functions = krealloc(pctl->functions, - pctl->nfunctions * sizeof(*pctl->functions), - GFP_KERNEL); + pctl->nfunctions * sizeof(*pctl->functions), + GFP_KERNEL); + if (!pctl->functions) { + kfree(pctl->functions); + return -ENOMEM; + } for (i = 0; i < pctl->desc->npins; i++) { const struct sunxi_desc_pin *pin = pctl->desc->pins + i; - struct sunxi_desc_function *func = pin->functions; + struct sunxi_desc_function *func; - while (func->name) { + if (pin->variant && !(pctl->variant & pin->variant)) + continue; + + for (func = pin->functions; func->name; func++) { struct sunxi_pinctrl_function *func_item; const char **func_grp; + if (func->variant && !(pctl->variant & func->variant)) + continue; + func_item = sunxi_pinctrl_find_function_by_name(pctl, func->name); if (!func_item) @@ -1116,7 +1146,6 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) func_grp++; *func_grp = pin->pin.name; - func++; } } @@ -1208,15 +1237,16 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, return 0; } -int sunxi_pinctrl_init(struct platform_device *pdev, - const struct sunxi_pinctrl_desc *desc) +int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, + const struct sunxi_pinctrl_desc *desc, + unsigned long variant) { struct device_node *node = pdev->dev.of_node; struct pinctrl_desc *pctrl_desc; struct pinctrl_pin_desc *pins; struct sunxi_pinctrl *pctl; struct resource *res; - int i, ret, last_pin; + int i, ret, last_pin, pin_idx; struct clk *clk; pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); @@ -1233,6 +1263,7 @@ int sunxi_pinctrl_init(struct platform_device *pdev, pctl->dev = &pdev->dev; pctl->desc = desc; + pctl->variant = variant; pctl->irq_array = devm_kcalloc(&pdev->dev, IRQ_PER_BANK * pctl->desc->irq_banks, @@ -1253,8 +1284,14 @@ int sunxi_pinctrl_init(struct platform_device *pdev, if (!pins) return -ENOMEM; - for (i = 0; i < pctl->desc->npins; i++) - pins[i] = pctl->desc->pins[i].pin; + for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) { + const struct sunxi_desc_pin *pin = pctl->desc->pins + i; + + if (pin->variant && !(pctl->variant & pin->variant)) + continue; + + pins[pin_idx++] = pin->pin; + } pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), @@ -1265,7 +1302,7 @@ int sunxi_pinctrl_init(struct platform_device *pdev, pctrl_desc->name = dev_name(&pdev->dev); pctrl_desc->owner = THIS_MODULE; pctrl_desc->pins = pins; - pctrl_desc->npins = pctl->desc->npins; + pctrl_desc->npins = pctl->ngroups; pctrl_desc->confops = &sunxi_pconf_ops; pctrl_desc->pctlops = &sunxi_pctrl_ops; pctrl_desc->pmxops = &sunxi_pmx_ops; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index f78a44a03189..539a3dd2d868 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -83,6 +83,7 @@ #define SUN4I_FUNC_IRQ 6 struct sunxi_desc_function { + unsigned long variant; const char *name; u8 muxval; u8 irqbank; @@ -91,6 +92,7 @@ struct sunxi_desc_function { struct sunxi_desc_pin { struct pinctrl_pin_desc pin; + unsigned long variant; struct sunxi_desc_function *functions; }; @@ -128,6 +130,7 @@ struct sunxi_pinctrl { unsigned *irq_array; spinlock_t lock; struct pinctrl_dev *pctl_dev; + unsigned long variant; }; #define SUNXI_PIN(_pin, ...) \ @@ -137,12 +140,27 @@ struct sunxi_pinctrl { __VA_ARGS__, { } }, \ } +#define SUNXI_PIN_VARIANT(_pin, _variant, ...) \ + { \ + .pin = _pin, \ + .variant = _variant, \ + .functions = (struct sunxi_desc_function[]){ \ + __VA_ARGS__, { } }, \ + } + #define SUNXI_FUNCTION(_val, _name) \ { \ .name = _name, \ .muxval = _val, \ } +#define SUNXI_FUNCTION_VARIANT(_val, _name, _variant) \ + { \ + .name = _name, \ + .muxval = _val, \ + .variant = _variant, \ + } + #define SUNXI_FUNCTION_IRQ(_val, _irq) \ { \ .name = "irq", \ @@ -290,7 +308,11 @@ static inline u32 sunxi_irq_status_offset(u16 irq) return irq_num * IRQ_STATUS_IRQ_BITS; } -int sunxi_pinctrl_init(struct platform_device *pdev, - const struct sunxi_pinctrl_desc *desc); +int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, + const struct sunxi_pinctrl_desc *desc, + unsigned long variant); + +#define sunxi_pinctrl_init(_dev, _desc) \ + sunxi_pinctrl_init_with_variant(_dev, _desc, 0) #endif /* __PINCTRL_SUNXI_H */ From 858f559f3dab00fda3fca4f187a315d5c9220fad Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sun, 8 Jan 2017 22:31:16 +0100 Subject: [PATCH 0275/1587] pinctrl: sunxi: Add common sun5i pinctrl driver The sun5i SoCs (A10s, A13, GR8) are all based on the same die fit in different packages. Hence, the pins and functions available are just the based on the same set, each SoC having a different subset. Introduce a common pinctrl driver that supports multiple variants to allow to put as much as we can in common. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/Kconfig | 3 + drivers/pinctrl/sunxi/Makefile | 1 + drivers/pinctrl/sunxi/pinctrl-sun5i.c | 756 ++++++++++++++++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 4 + 4 files changed, 764 insertions(+) create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun5i.c diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index bff1ffc6f01e..dd82b197f052 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -9,6 +9,9 @@ config PINCTRL_SUN4I_A10 def_bool MACH_SUN4I select PINCTRL_SUNXI +config PINCTRL_SUN5I + select PINCTRL_SUNXI + config PINCTRL_SUN5I_A10S def_bool MACH_SUN5I select PINCTRL_SUNXI diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index 95f93d0561fc..2037e99ae3fc 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -3,6 +3,7 @@ obj-y += pinctrl-sunxi.o # SoC Drivers obj-$(CONFIG_PINCTRL_SUN4I_A10) += pinctrl-sun4i-a10.o +obj-$(CONFIG_PINCTRL_SUN5I) += pinctrl-sun5i.o obj-$(CONFIG_PINCTRL_SUN5I_A10S) += pinctrl-sun5i-a10s.o obj-$(CONFIG_PINCTRL_SUN5I_A13) += pinctrl-sun5i-a13.o obj-$(CONFIG_PINCTRL_GR8) += pinctrl-gr8.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i.c b/drivers/pinctrl/sunxi/pinctrl-sun5i.c new file mode 100644 index 000000000000..c8a94323ce8b --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun5i.c @@ -0,0 +1,756 @@ +/* + * Allwinner sun5i SoCs pinctrl driver. + * + * Copyright (C) 2014-2016 Maxime Ripard + * Copyright (C) 2016 Mylene Josserand + * +g * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-sunxi.h" + +static const struct sunxi_desc_pin sun5i_pins[] = { + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 0), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD3 */ + SUNXI_FUNCTION(0x3, "ts0"), /* CLK */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN0 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 1), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD2 */ + SUNXI_FUNCTION(0x3, "ts0"), /* ERR */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN1 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 2), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD1 */ + SUNXI_FUNCTION(0x3, "ts0"), /* SYNC */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN2 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 3), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD0 */ + SUNXI_FUNCTION(0x3, "ts0"), /* DLVD */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN3 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 4), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD3 */ + SUNXI_FUNCTION(0x3, "ts0"), /* D0 */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN4 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 5), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD2 */ + SUNXI_FUNCTION(0x3, "ts0"), /* D1 */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN5 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 6), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD1 */ + SUNXI_FUNCTION(0x3, "ts0"), /* D2 */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN6 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 7), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD0 */ + SUNXI_FUNCTION(0x3, "ts0"), /* D3 */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN7 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 8), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXCK */ + SUNXI_FUNCTION(0x3, "ts0"), /* D4 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DTR */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT0 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 9), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXERR */ + SUNXI_FUNCTION(0x3, "ts0"), /* D5 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DSR */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT1 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 10), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXDV */ + SUNXI_FUNCTION(0x3, "ts0"), /* D6 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DCD */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT2 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 11), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* EMDC */ + SUNXI_FUNCTION(0x3, "ts0"), /* D7 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RING */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT3 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 12), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* EMDIO */ + SUNXI_FUNCTION(0x3, "uart1"), /* TX */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT4 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 13), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXEN */ + SUNXI_FUNCTION(0x3, "uart1"), /* RX */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT5 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 14), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXCK */ + SUNXI_FUNCTION(0x3, "uart1"), /* CTS */ + SUNXI_FUNCTION(0x4, "uart3"), /* TX */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT6 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 15), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ECRS */ + SUNXI_FUNCTION(0x3, "uart1"), /* RTS */ + SUNXI_FUNCTION(0x4, "uart3"), /* RX */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT7 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 16), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ECOL */ + SUNXI_FUNCTION(0x3, "uart2")), /* TX */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 17), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXERR */ + SUNXI_FUNCTION(0x3, "uart2"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 31)), /* EINT31 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm"), /* PWM0 */ + SUNXI_FUNCTION_VARIANT(0x3, + "spdif", /* DO */ + PINCTRL_SUN5I_GR8), + SUNXI_FUNCTION_IRQ(0x6, 16)), /* EINT16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ir0"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 17)), /* EINT17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ir0"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 18)), /* EINT18 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 5), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* MCLK */ + SUNXI_FUNCTION_IRQ(0x6, 19)), /* EINT19 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 6), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* BCLK */ + SUNXI_FUNCTION_IRQ(0x6, 20)), /* EINT20 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 7), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* LRCK */ + SUNXI_FUNCTION_IRQ(0x6, 21)), /* EINT21 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 8), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* DO */ + SUNXI_FUNCTION_IRQ(0x6, 22)), /* EINT22 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 9), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* DI */ + SUNXI_FUNCTION_VARIANT(0x3, + "spdif", /* DI */ + PINCTRL_SUN5I_GR8), + SUNXI_FUNCTION_IRQ(0x6, 23)), /* EINT23 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CS1 */ + SUNXI_FUNCTION_VARIANT(0x3, + "spdif", /* DO */ + PINCTRL_SUN5I_GR8), + SUNXI_FUNCTION_IRQ(0x6, 24)), /* EINT24 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 11), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */ + SUNXI_FUNCTION(0x3, "jtag"), /* MS0 */ + SUNXI_FUNCTION_IRQ(0x6, 25)), /* EINT25 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 12), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CLK */ + SUNXI_FUNCTION(0x3, "jtag"), /* CK0 */ + SUNXI_FUNCTION_IRQ(0x6, 26)), /* EINT26 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 13), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */ + SUNXI_FUNCTION(0x3, "jtag"), /* DO0 */ + SUNXI_FUNCTION_IRQ(0x6, 27)), /* EINT27 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 14), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* MISO */ + SUNXI_FUNCTION(0x3, "jtag"), /* DI0 */ + SUNXI_FUNCTION_IRQ(0x6, 28)), /* EINT28 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 19), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 29)), /* EINT29 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 20), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 30)), /* EINT30 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ + SUNXI_FUNCTION(0x3, "spi0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */ + SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NRE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 16), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NWP */ + SUNXI_FUNCTION(0x4, "uart3")), /* TX */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 17), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE2 */ + SUNXI_FUNCTION(0x4, "uart3")), /* RX */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 18), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE3 */ + SUNXI_FUNCTION(0x3, "uart2"), /* TX */ + SUNXI_FUNCTION(0x4, "uart3")), /* CTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE4 */ + SUNXI_FUNCTION(0x3, "uart2"), /* RX */ + SUNXI_FUNCTION(0x4, "uart3")), /* RTS */ + /* Hole */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 0), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D0 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 1), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ + SUNXI_FUNCTION(0x3, "uart2")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ + SUNXI_FUNCTION(0x3, "uart2")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ + SUNXI_FUNCTION(0x3, "uart2")), /* CTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ + SUNXI_FUNCTION(0x3, "uart2")), /* RTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ + SUNXI_FUNCTION(0x3, "emac")), /* ECRS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ + SUNXI_FUNCTION(0x3, "emac")), /* ECOL */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 8), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D8 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 9), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXD0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXD1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXD2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXD3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXERR */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 16), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D16 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 17), + PINCTRL_SUN5I_A10S, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXDV */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXD0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXD1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXD2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXD3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXEN */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* DE */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXERR */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */ + SUNXI_FUNCTION(0x3, "emac")), /* EMDC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */ + SUNXI_FUNCTION(0x3, "emac")), /* EMDIO */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "ts0"), /* CLK */ + SUNXI_FUNCTION(0x3, "csi0"), /* PCK */ + SUNXI_FUNCTION(0x4, "spi2"), /* CS0 */ + SUNXI_FUNCTION_IRQ(0x6, 14)), /* EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "ts0"), /* ERR */ + SUNXI_FUNCTION(0x3, "csi0"), /* CK */ + SUNXI_FUNCTION(0x4, "spi2"), /* CLK */ + SUNXI_FUNCTION_IRQ(0x6, 15)), /* EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "ts0"), /* SYNC */ + SUNXI_FUNCTION(0x3, "csi0"), /* HSYNC */ + SUNXI_FUNCTION(0x4, "spi2")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* DVLD */ + SUNXI_FUNCTION(0x3, "csi0"), /* VSYNC */ + SUNXI_FUNCTION(0x4, "spi2")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D0 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D0 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D1 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D2 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D2 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D3 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D3 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D4 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D4 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D5 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D5 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D6 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D6 */ + SUNXI_FUNCTION(0x4, "uart1")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D7 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D7 */ + SUNXI_FUNCTION(0x4, "uart1")), /* RX */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ + SUNXI_FUNCTION(0x4, "jtag")), /* MS1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ + SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ + SUNXI_FUNCTION(0x4, "jtag")), /* DO1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ + SUNXI_FUNCTION(0x4, "uart0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ + SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "gps"), /* CLK */ + SUNXI_FUNCTION_IRQ(0x6, 0)), /* EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "gps"), /* SIGN */ + SUNXI_FUNCTION_IRQ(0x6, 1)), /* EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "gps"), /* MAG */ + SUNXI_FUNCTION_IRQ(0x6, 2)), /* EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ + SUNXI_FUNCTION(0x4, "uart1"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 3)), /* EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart1"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 4)), /* EINT4 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 5), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* DO */ + SUNXI_FUNCTION(0x4, "uart1"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 5)), /* EINT5 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 6), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RTS */ + SUNXI_FUNCTION(0x5, "uart2"), /* RTS */ + SUNXI_FUNCTION_IRQ(0x6, 6)), /* EINT6 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 7), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */ + SUNXI_FUNCTION(0x5, "uart2"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 7)), /* EINT7 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 8), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */ + SUNXI_FUNCTION(0x5, "uart2"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 8)), /* EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ + SUNXI_FUNCTION(0x3, "uart3"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 9)), /* EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ + SUNXI_FUNCTION(0x3, "uart3"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 10)), /* EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ + SUNXI_FUNCTION(0x3, "uart3"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 11)), /* EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ + SUNXI_FUNCTION(0x3, "uart3"), /* RTS */ + SUNXI_FUNCTION_IRQ(0x6, 12)), /* EINT12 */ + SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 13), + PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */ + SUNXI_FUNCTION(0x3, "pwm"), /* PWM1 */ + SUNXI_FUNCTION(0x5, "uart2"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 13)), /* EINT13 */ +}; + +static const struct sunxi_pinctrl_desc sun5i_pinctrl_data = { + .pins = sun5i_pins, + .npins = ARRAY_SIZE(sun5i_pins), + .irq_banks = 1, +}; + +static int sun5i_pinctrl_probe(struct platform_device *pdev) +{ + unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); + + printk("prout\n"); + + return sunxi_pinctrl_init_with_variant(pdev, &sun5i_pinctrl_data, + variant); +} + +static const struct of_device_id sun5i_pinctrl_match[] = { + { + .compatible = "allwinner,sun5i-a10s-pinctrl", + .data = (void *)PINCTRL_SUN5I_A10S + }, + { + .compatible = "allwinner,sun5i-a13-pinctrl", + .data = (void *)PINCTRL_SUN5I_A13 + }, + { + .compatible = "nextthing,gr8-pinctrl", + .data = (void *)PINCTRL_SUN5I_GR8 + }, + { }, +}; +MODULE_DEVICE_TABLE(of, sun5i_pinctrl_match); + +static struct platform_driver sun5i_pinctrl_driver = { + .probe = sun5i_pinctrl_probe, + .driver = { + .name = "sun5i-pinctrl", + .of_match_table = sun5i_pinctrl_match, + }, +}; +module_platform_driver(sun5i_pinctrl_driver); + +MODULE_AUTHOR("Maxime Ripard Date: Sun, 8 Jan 2017 22:31:17 +0100 Subject: [PATCH 0276/1587] pinctrl: sunxi: Remove old sun5i pinctrl drivers Now that we have a common pinctrl driver for all the sun5i SoCs, we can remove the old, separate drivers. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/Kconfig | 11 - drivers/pinctrl/sunxi/Makefile | 3 - drivers/pinctrl/sunxi/pinctrl-gr8.c | 536 ---------------- drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c | 685 --------------------- drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c | 403 ------------ 5 files changed, 1638 deletions(-) delete mode 100644 drivers/pinctrl/sunxi/pinctrl-gr8.c delete mode 100644 drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c delete mode 100644 drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index dd82b197f052..c9f3434f6793 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -10,20 +10,9 @@ config PINCTRL_SUN4I_A10 select PINCTRL_SUNXI config PINCTRL_SUN5I - select PINCTRL_SUNXI - -config PINCTRL_SUN5I_A10S def_bool MACH_SUN5I select PINCTRL_SUNXI -config PINCTRL_SUN5I_A13 - def_bool MACH_SUN5I - select PINCTRL_SUNXI - -config PINCTRL_GR8 - def_bool MACH_SUN5I - select PINCTRL_SUNXI_COMMON - config PINCTRL_SUN6I_A31 def_bool MACH_SUN6I select PINCTRL_SUNXI diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index 2037e99ae3fc..4178408d3705 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -4,9 +4,6 @@ obj-y += pinctrl-sunxi.o # SoC Drivers obj-$(CONFIG_PINCTRL_SUN4I_A10) += pinctrl-sun4i-a10.o obj-$(CONFIG_PINCTRL_SUN5I) += pinctrl-sun5i.o -obj-$(CONFIG_PINCTRL_SUN5I_A10S) += pinctrl-sun5i-a10s.o -obj-$(CONFIG_PINCTRL_SUN5I_A13) += pinctrl-sun5i-a13.o -obj-$(CONFIG_PINCTRL_GR8) += pinctrl-gr8.o obj-$(CONFIG_PINCTRL_SUN6I_A31) += pinctrl-sun6i-a31.o obj-$(CONFIG_PINCTRL_SUN6I_A31S) += pinctrl-sun6i-a31s.o obj-$(CONFIG_PINCTRL_SUN6I_A31_R) += pinctrl-sun6i-a31-r.o diff --git a/drivers/pinctrl/sunxi/pinctrl-gr8.c b/drivers/pinctrl/sunxi/pinctrl-gr8.c deleted file mode 100644 index 2f232c3a0579..000000000000 --- a/drivers/pinctrl/sunxi/pinctrl-gr8.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * NextThing GR8 SoCs pinctrl driver. - * - * Copyright (C) 2016 Mylene Josserand - * - * Based on pinctrl-sun5i-a13.c - * - * Mylene Josserand - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include - -#include "pinctrl-sunxi.h" - -static const struct sunxi_desc_pin sun5i_gr8_pins[] = { - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "pwm0"), - SUNXI_FUNCTION(0x3, "spdif"), /* DO */ - SUNXI_FUNCTION_IRQ(0x6, 16)), /* EINT16 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 17)), /* EINT17 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 18)), /* EINT18 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s0"), /* MCLK */ - SUNXI_FUNCTION_IRQ(0x6, 19)), /* EINT19 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s0"), /* BCLK */ - SUNXI_FUNCTION_IRQ(0x6, 20)), /* EINT20 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s0"), /* LRCK */ - SUNXI_FUNCTION_IRQ(0x6, 21)), /* EINT21 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s0"), /* DO */ - SUNXI_FUNCTION_IRQ(0x6, 22)), /* EINT22 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s0"), /* DI */ - SUNXI_FUNCTION(0x3, "spdif"), /* DI */ - SUNXI_FUNCTION_IRQ(0x6, 23)), /* EINT23 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CS1 */ - SUNXI_FUNCTION(0x3, "spdif"), /* DO */ - SUNXI_FUNCTION_IRQ(0x6, 24)), /* EINT24 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */ - SUNXI_FUNCTION(0x3, "jtag"), /* MS0 */ - SUNXI_FUNCTION_IRQ(0x6, 25)), /* EINT25 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CLK */ - SUNXI_FUNCTION(0x3, "jtag"), /* CK0 */ - SUNXI_FUNCTION_IRQ(0x6, 26)), /* EINT26 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */ - SUNXI_FUNCTION(0x3, "jtag"), /* DO0 */ - SUNXI_FUNCTION_IRQ(0x6, 27)), /* EINT27 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* MISO */ - SUNXI_FUNCTION(0x3, "jtag"), /* DI0 */ - SUNXI_FUNCTION_IRQ(0x6, 28)), /* EINT28 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 17), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 18), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ - SUNXI_FUNCTION(0x3, "spi0")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */ - SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NRE */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQS */ - SUNXI_FUNCTION(0x3, "uart2"), /* RX */ - SUNXI_FUNCTION(0x4, "uart3")), /* RTS */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ - SUNXI_FUNCTION(0x3, "uart2")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ - SUNXI_FUNCTION(0x3, "uart2")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ - SUNXI_FUNCTION(0x3, "uart2")), /* CTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ - SUNXI_FUNCTION(0x3, "uart2")), /* RTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ - SUNXI_FUNCTION(0x3, "emac")), /* ECRS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ - SUNXI_FUNCTION(0x3, "emac")), /* ECOL */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXD0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXD1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXD2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXD3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXERR */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXDV */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXD0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXD1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXD2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXD3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXEN */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* DE */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXERR*/ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */ - SUNXI_FUNCTION(0x3, "emac")), /* EMDC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */ - SUNXI_FUNCTION(0x3, "emac")), /* EMDIO */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "ts0"), /* CLK */ - SUNXI_FUNCTION(0x3, "csi0"), /* PCLK */ - SUNXI_FUNCTION(0x4, "spi2"), /* CS0 */ - SUNXI_FUNCTION_IRQ(0x6, 14)), /* EINT14 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "ts0"), /* ERR */ - SUNXI_FUNCTION(0x3, "csi0"), /* MCLK */ - SUNXI_FUNCTION(0x4, "spi2"), /* CLK */ - SUNXI_FUNCTION_IRQ(0x6, 15)), /* EINT15 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "ts0"), /* SYNC */ - SUNXI_FUNCTION(0x3, "csi0"), /* HSYNC */ - SUNXI_FUNCTION(0x4, "spi2")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* DVLD */ - SUNXI_FUNCTION(0x3, "csi0"), /* VSYNC */ - SUNXI_FUNCTION(0x4, "spi2")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D0 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D0 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D1 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D2 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D2 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D3 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D3 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D4 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D4 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D5 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D5 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D6 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D6 */ - SUNXI_FUNCTION(0x4, "uart1")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D7 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D7 */ - SUNXI_FUNCTION(0x4, "uart1")), /* RX */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ - SUNXI_FUNCTION(0x4, "jtag")), /* MS1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ - SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ - SUNXI_FUNCTION(0x4, "uart0")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ - SUNXI_FUNCTION(0x4, "jtag")), /* DO1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ - SUNXI_FUNCTION(0x4, "uart0")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ - SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "gps"), /* CLK */ - SUNXI_FUNCTION_IRQ(0x6, 0)), /* EINT0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "gps"), /* SIGN */ - SUNXI_FUNCTION_IRQ(0x6, 1)), /* EINT1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "gps"), /* MAG */ - SUNXI_FUNCTION_IRQ(0x6, 2)), /* EINT2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ - SUNXI_FUNCTION(0x3, "ms"), /* BS */ - SUNXI_FUNCTION(0x4, "uart1"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 3)), /* EINT3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ - SUNXI_FUNCTION(0x3, "ms"), /* CLK */ - SUNXI_FUNCTION(0x4, "uart1"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 4)), /* EINT4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */ - SUNXI_FUNCTION(0x3, "ms"), /* D0 */ - SUNXI_FUNCTION(0x4, "uart1"), /* CTS */ - SUNXI_FUNCTION_IRQ(0x6, 5)), /* EINT5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */ - SUNXI_FUNCTION(0x3, "ms"), /* D1 */ - SUNXI_FUNCTION(0x4, "uart1"), /* RTS */ - SUNXI_FUNCTION(0x5, "uart2"), /* RTS */ - SUNXI_FUNCTION_IRQ(0x6, 6)), /* EINT6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */ - SUNXI_FUNCTION(0x3, "ms"), /* D2 */ - SUNXI_FUNCTION(0x5, "uart2"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 7)), /* EINT7 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */ - SUNXI_FUNCTION(0x3, "ms"), /* D3 */ - SUNXI_FUNCTION(0x5, "uart2"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 8)), /* EINT8 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ - SUNXI_FUNCTION(0x3, "uart3"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 9)), /* EINT9 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ - SUNXI_FUNCTION(0x3, "uart3"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 10)), /* EINT10 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ - SUNXI_FUNCTION(0x3, "uart3"), /* CTS */ - SUNXI_FUNCTION_IRQ(0x6, 11)), /* EINT11 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ - SUNXI_FUNCTION(0x3, "uart3"), /* RTS */ - SUNXI_FUNCTION_IRQ(0x6, 12)), /* EINT12 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */ - SUNXI_FUNCTION(0x3, "pwm1"), - SUNXI_FUNCTION(0x5, "uart2"), /* CTS */ - SUNXI_FUNCTION_IRQ(0x6, 13)), /* EINT13 */ -}; - -static const struct sunxi_pinctrl_desc sun5i_gr8_pinctrl_data = { - .pins = sun5i_gr8_pins, - .npins = ARRAY_SIZE(sun5i_gr8_pins), - .irq_banks = 1, -}; - -static int sun5i_gr8_pinctrl_probe(struct platform_device *pdev) -{ - return sunxi_pinctrl_init(pdev, - &sun5i_gr8_pinctrl_data); -} - -static const struct of_device_id sun5i_gr8_pinctrl_match[] = { - { .compatible = "nextthing,gr8-pinctrl", }, - {} -}; - -static struct platform_driver sun5i_gr8_pinctrl_driver = { - .probe = sun5i_gr8_pinctrl_probe, - .driver = { - .name = "gr8-pinctrl", - .of_match_table = sun5i_gr8_pinctrl_match, - }, -}; -builtin_platform_driver(sun5i_gr8_pinctrl_driver); diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c b/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c deleted file mode 100644 index a5b57fdff9e1..000000000000 --- a/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * Allwinner A10s SoCs pinctrl driver. - * - * Copyright (C) 2014 Maxime Ripard - * - * Maxime Ripard - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include - -#include "pinctrl-sunxi.h" - -static const struct sunxi_desc_pin sun5i_a10s_pins[] = { - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXD3 */ - SUNXI_FUNCTION(0x3, "ts0"), /* CLK */ - SUNXI_FUNCTION(0x5, "keypad")), /* IN0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXD2 */ - SUNXI_FUNCTION(0x3, "ts0"), /* ERR */ - SUNXI_FUNCTION(0x5, "keypad")), /* IN1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXD1 */ - SUNXI_FUNCTION(0x3, "ts0"), /* SYNC */ - SUNXI_FUNCTION(0x5, "keypad")), /* IN2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXD0 */ - SUNXI_FUNCTION(0x3, "ts0"), /* DLVD */ - SUNXI_FUNCTION(0x5, "keypad")), /* IN3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXD3 */ - SUNXI_FUNCTION(0x3, "ts0"), /* D0 */ - SUNXI_FUNCTION(0x5, "keypad")), /* IN4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXD2 */ - SUNXI_FUNCTION(0x3, "ts0"), /* D1 */ - SUNXI_FUNCTION(0x5, "keypad")), /* IN5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXD1 */ - SUNXI_FUNCTION(0x3, "ts0"), /* D2 */ - SUNXI_FUNCTION(0x5, "keypad")), /* IN6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXD0 */ - SUNXI_FUNCTION(0x3, "ts0"), /* D3 */ - SUNXI_FUNCTION(0x5, "keypad")), /* IN7 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXCK */ - SUNXI_FUNCTION(0x3, "ts0"), /* D4 */ - SUNXI_FUNCTION(0x4, "uart1"), /* DTR */ - SUNXI_FUNCTION(0x5, "keypad")), /* OUT0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXERR */ - SUNXI_FUNCTION(0x3, "ts0"), /* D5 */ - SUNXI_FUNCTION(0x4, "uart1"), /* DSR */ - SUNXI_FUNCTION(0x5, "keypad")), /* OUT1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXDV */ - SUNXI_FUNCTION(0x3, "ts0"), /* D6 */ - SUNXI_FUNCTION(0x4, "uart1"), /* DCD */ - SUNXI_FUNCTION(0x5, "keypad")), /* OUT2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* EMDC */ - SUNXI_FUNCTION(0x3, "ts0"), /* D7 */ - SUNXI_FUNCTION(0x4, "uart1"), /* RING */ - SUNXI_FUNCTION(0x5, "keypad")), /* OUT3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* EMDIO */ - SUNXI_FUNCTION(0x3, "uart1"), /* TX */ - SUNXI_FUNCTION(0x5, "keypad")), /* OUT4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXEN */ - SUNXI_FUNCTION(0x3, "uart1"), /* RX */ - SUNXI_FUNCTION(0x5, "keypad")), /* OUT5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXCK */ - SUNXI_FUNCTION(0x3, "uart1"), /* CTS */ - SUNXI_FUNCTION(0x4, "uart3"), /* TX */ - SUNXI_FUNCTION(0x5, "keypad")), /* OUT6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ECRS */ - SUNXI_FUNCTION(0x3, "uart1"), /* RTS */ - SUNXI_FUNCTION(0x4, "uart3"), /* RX */ - SUNXI_FUNCTION(0x5, "keypad")), /* OUT7 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ECOL */ - SUNXI_FUNCTION(0x3, "uart2")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXERR */ - SUNXI_FUNCTION(0x3, "uart2"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 31)), /* EINT31 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "pwm"), /* PWM0 */ - SUNXI_FUNCTION_IRQ(0x6, 16)), /* EINT16 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 17)), /* EINT17 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 18)), /* EINT18 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* MCLK */ - SUNXI_FUNCTION_IRQ(0x6, 19)), /* EINT19 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* BCLK */ - SUNXI_FUNCTION_IRQ(0x6, 20)), /* EINT20 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* LRCK */ - SUNXI_FUNCTION_IRQ(0x6, 21)), /* EINT21 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* DO */ - SUNXI_FUNCTION_IRQ(0x6, 22)), /* EINT22 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* DI */ - SUNXI_FUNCTION_IRQ(0x6, 23)), /* EINT23 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CS1 */ - SUNXI_FUNCTION_IRQ(0x6, 24)), /* EINT24 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */ - SUNXI_FUNCTION(0x3, "jtag"), /* MS0 */ - SUNXI_FUNCTION_IRQ(0x6, 25)), /* EINT25 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CLK */ - SUNXI_FUNCTION(0x3, "jtag"), /* CK0 */ - SUNXI_FUNCTION_IRQ(0x6, 26)), /* EINT26 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */ - SUNXI_FUNCTION(0x3, "jtag"), /* DO0 */ - SUNXI_FUNCTION_IRQ(0x6, 27)), /* EINT27 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* MISO */ - SUNXI_FUNCTION(0x3, "jtag"), /* DI0 */ - SUNXI_FUNCTION_IRQ(0x6, 28)), /* EINT28 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 17), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 18), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 19), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "uart0"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 29)), /* EINT29 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 20), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "uart0"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 30)), /* EINT30 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ - SUNXI_FUNCTION(0x3, "spi0")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */ - SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NRE */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NWP */ - SUNXI_FUNCTION(0x4, "uart3")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE2 */ - SUNXI_FUNCTION(0x4, "uart3")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE3 */ - SUNXI_FUNCTION(0x3, "uart2"), /* TX */ - SUNXI_FUNCTION(0x4, "uart3")), /* CTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE4 */ - SUNXI_FUNCTION(0x3, "uart2"), /* RX */ - SUNXI_FUNCTION(0x4, "uart3")), /* RTS */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ - SUNXI_FUNCTION(0x3, "uart2")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ - SUNXI_FUNCTION(0x3, "uart2")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ - SUNXI_FUNCTION(0x3, "uart2")), /* CTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ - SUNXI_FUNCTION(0x3, "uart2")), /* RTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ - SUNXI_FUNCTION(0x3, "emac")), /* ECRS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ - SUNXI_FUNCTION(0x3, "emac")), /* ECOL */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D8 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D9 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXD0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXD1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXD2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXD3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXERR */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D16 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D17 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */ - SUNXI_FUNCTION(0x3, "emac")), /* ERXDV */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXD0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXD1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXD2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXD3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXEN */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* DE */ - SUNXI_FUNCTION(0x3, "emac")), /* ETXERR */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */ - SUNXI_FUNCTION(0x3, "emac")), /* EMDC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */ - SUNXI_FUNCTION(0x3, "emac")), /* EMDIO */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "ts0"), /* CLK */ - SUNXI_FUNCTION(0x3, "csi0"), /* PCK */ - SUNXI_FUNCTION(0x4, "spi2"), /* CS0 */ - SUNXI_FUNCTION_IRQ(0x6, 14)), /* EINT14 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "ts0"), /* ERR */ - SUNXI_FUNCTION(0x3, "csi0"), /* CK */ - SUNXI_FUNCTION(0x4, "spi2"), /* CLK */ - SUNXI_FUNCTION_IRQ(0x6, 15)), /* EINT15 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "ts0"), /* SYNC */ - SUNXI_FUNCTION(0x3, "csi0"), /* HSYNC */ - SUNXI_FUNCTION(0x4, "spi2")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* DVLD */ - SUNXI_FUNCTION(0x3, "csi0"), /* VSYNC */ - SUNXI_FUNCTION(0x4, "spi2")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D0 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D0 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D1 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D2 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D2 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D3 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D3 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D4 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D4 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D5 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D5 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D6 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D6 */ - SUNXI_FUNCTION(0x4, "uart1")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D7 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D7 */ - SUNXI_FUNCTION(0x4, "uart1")), /* RX */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ - SUNXI_FUNCTION(0x4, "jtag")), /* MS1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ - SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ - SUNXI_FUNCTION(0x4, "uart0")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ - SUNXI_FUNCTION(0x4, "jtag")), /* DO1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ - SUNXI_FUNCTION(0x4, "uart0")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ - SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "gps"), /* CLK */ - SUNXI_FUNCTION_IRQ(0x6, 0)), /* EINT0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "gps"), /* SIGN */ - SUNXI_FUNCTION_IRQ(0x6, 1)), /* EINT1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x2, "gps"), /* MAG */ - SUNXI_FUNCTION_IRQ(0x6, 2)), /* EINT2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ - SUNXI_FUNCTION(0x4, "uart1"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 3)), /* EINT3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ - SUNXI_FUNCTION(0x4, "uart1"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 4)), /* EINT4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* DO */ - SUNXI_FUNCTION(0x4, "uart1"), /* CTS */ - SUNXI_FUNCTION_IRQ(0x6, 5)), /* EINT5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */ - SUNXI_FUNCTION(0x4, "uart1"), /* RTS */ - SUNXI_FUNCTION(0x5, "uart2"), /* RTS */ - SUNXI_FUNCTION_IRQ(0x6, 6)), /* EINT6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */ - SUNXI_FUNCTION(0x5, "uart2"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 7)), /* EINT7 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */ - SUNXI_FUNCTION(0x5, "uart2"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 8)), /* EINT8 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ - SUNXI_FUNCTION(0x3, "uart3"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 9)), /* EINT9 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ - SUNXI_FUNCTION(0x3, "uart3"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 10)), /* EINT10 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ - SUNXI_FUNCTION(0x3, "uart3"), /* CTS */ - SUNXI_FUNCTION_IRQ(0x6, 11)), /* EINT11 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ - SUNXI_FUNCTION(0x3, "uart3"), /* RTS */ - SUNXI_FUNCTION_IRQ(0x6, 12)), /* EINT12 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */ - SUNXI_FUNCTION(0x3, "pwm"), /* PWM1 */ - SUNXI_FUNCTION(0x5, "uart2"), /* CTS */ - SUNXI_FUNCTION_IRQ(0x6, 13)), /* EINT13 */ -}; - -static const struct sunxi_pinctrl_desc sun5i_a10s_pinctrl_data = { - .pins = sun5i_a10s_pins, - .npins = ARRAY_SIZE(sun5i_a10s_pins), - .irq_banks = 1, -}; - -static int sun5i_a10s_pinctrl_probe(struct platform_device *pdev) -{ - return sunxi_pinctrl_init(pdev, - &sun5i_a10s_pinctrl_data); -} - -static const struct of_device_id sun5i_a10s_pinctrl_match[] = { - { .compatible = "allwinner,sun5i-a10s-pinctrl", }, - {} -}; - -static struct platform_driver sun5i_a10s_pinctrl_driver = { - .probe = sun5i_a10s_pinctrl_probe, - .driver = { - .name = "sun5i-a10s-pinctrl", - .of_match_table = sun5i_a10s_pinctrl_match, - }, -}; -builtin_platform_driver(sun5i_a10s_pinctrl_driver); diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c b/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c deleted file mode 100644 index 8575f3f6d3dd..000000000000 --- a/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Allwinner A13 SoCs pinctrl driver. - * - * Copyright (C) 2014 Maxime Ripard - * - * Maxime Ripard - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include - -#include "pinctrl-sunxi.h" - -static const struct sunxi_desc_pin sun5i_a13_pins[] = { - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "pwm"), - SUNXI_FUNCTION_IRQ(0x6, 16)), /* EINT16 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 17)), /* EINT17 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 18)), /* EINT18 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CS1 */ - SUNXI_FUNCTION_IRQ(0x6, 24)), /* EINT24 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 17), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 18), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ - SUNXI_FUNCTION(0x3, "spi0")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */ - SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NRE */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQS */ - SUNXI_FUNCTION(0x4, "uart3")), /* RTS */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D7 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D10 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D11 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D12 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D13 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D14 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D15 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D18 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D19 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D20 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D21 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D22 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D23 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* DE */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* HSYNC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* VSYNC */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x3, "csi0"), /* PCLK */ - SUNXI_FUNCTION(0x4, "spi2"), /* CS0 */ - SUNXI_FUNCTION_IRQ(0x6, 14)), /* EINT14 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x3, "csi0"), /* MCLK */ - SUNXI_FUNCTION(0x4, "spi2"), /* CLK */ - SUNXI_FUNCTION_IRQ(0x6, 15)), /* EINT15 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x3, "csi0"), /* HSYNC */ - SUNXI_FUNCTION(0x4, "spi2")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* VSYNC */ - SUNXI_FUNCTION(0x4, "spi2")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D0 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D2 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D3 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D4 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D5 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D6 */ - SUNXI_FUNCTION(0x4, "uart1")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D7 */ - SUNXI_FUNCTION(0x4, "uart1")), /* RX */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0")), /* D2 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION_IRQ(0x6, 0)), /* EINT0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION_IRQ(0x6, 1)), /* EINT1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION_IRQ(0x6, 2)), /* EINT2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ - SUNXI_FUNCTION(0x4, "uart1"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 3)), /* EINT3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ - SUNXI_FUNCTION(0x4, "uart1"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 4)), /* EINT4 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ - SUNXI_FUNCTION(0x3, "uart3"), /* TX */ - SUNXI_FUNCTION_IRQ(0x6, 9)), /* EINT9 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ - SUNXI_FUNCTION(0x3, "uart3"), /* RX */ - SUNXI_FUNCTION_IRQ(0x6, 10)), /* EINT10 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ - SUNXI_FUNCTION(0x3, "uart3"), /* CTS */ - SUNXI_FUNCTION_IRQ(0x6, 11)), /* EINT11 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12), - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ - SUNXI_FUNCTION(0x3, "uart3"), /* RTS */ - SUNXI_FUNCTION_IRQ(0x6, 12)), /* EINT12 */ -}; - -static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = { - .pins = sun5i_a13_pins, - .npins = ARRAY_SIZE(sun5i_a13_pins), - .irq_banks = 1, -}; - -static int sun5i_a13_pinctrl_probe(struct platform_device *pdev) -{ - return sunxi_pinctrl_init(pdev, - &sun5i_a13_pinctrl_data); -} - -static const struct of_device_id sun5i_a13_pinctrl_match[] = { - { .compatible = "allwinner,sun5i-a13-pinctrl", }, - {} -}; - -static struct platform_driver sun5i_a13_pinctrl_driver = { - .probe = sun5i_a13_pinctrl_probe, - .driver = { - .name = "sun5i-a13-pinctrl", - .of_match_table = sun5i_a13_pinctrl_match, - }, -}; -builtin_platform_driver(sun5i_a13_pinctrl_driver); From da69a5306ab92e07224da54aafee8b1dccf024f6 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 9 Jan 2017 10:07:30 -0500 Subject: [PATCH 0277/1587] selinux: support distinctions among all network address families Extend SELinux to support distinctions among all network address families implemented by the kernel by defining new socket security classes and mapping to them. Otherwise, many sockets are mapped to the generic socket class and are indistinguishable in policy. This has come up previously with regard to selectively allowing access to bluetooth sockets, and more recently with regard to selectively allowing access to AF_ALG sockets. Guido Trentalancia submitted a patch that took a similar approach to add only support for distinguishing AF_ALG sockets, but this generalizes his approach to handle all address families implemented by the kernel. Socket security classes are also added for ICMP and SCTP sockets. Socket security classes were not defined for AF_* values that are reserved but unimplemented in the kernel, e.g. AF_NETBEUI, AF_SECURITY, AF_ASH, AF_ECONET, AF_SNA, AF_WANPIPE. Backward compatibility is provided by only enabling the finer-grained socket classes if a new policy capability is set in the policy; older policies will behave as before. The legacy redhat1 policy capability that was only ever used in testing within Fedora for ptrace_child is reclaimed for this purpose; as far as I can tell, this policy capability is not enabled in any supported distro policy. Add a pair of conditional compilation guards to detect when new AF_* values are added so that we can update SELinux accordingly rather than having to belatedly update it long after new address families are introduced. Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 73 +++++++++++++++++++++++++++++ security/selinux/include/classmap.h | 68 +++++++++++++++++++++++++++ security/selinux/include/security.h | 3 +- security/selinux/selinuxfs.c | 2 +- security/selinux/ss/services.c | 3 ++ 5 files changed, 147 insertions(+), 2 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c7c6619431d5..74cd3a689cf8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1268,6 +1268,8 @@ static inline int default_protocol_dgram(int protocol) static inline u16 socket_type_to_security_class(int family, int type, int protocol) { + int extsockclass = selinux_policycap_extsockclass; + switch (family) { case PF_UNIX: switch (type) { @@ -1282,13 +1284,18 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc case PF_INET6: switch (type) { case SOCK_STREAM: + case SOCK_SEQPACKET: if (default_protocol_stream(protocol)) return SECCLASS_TCP_SOCKET; + else if (extsockclass && protocol == IPPROTO_SCTP) + return SECCLASS_SCTP_SOCKET; else return SECCLASS_RAWIP_SOCKET; case SOCK_DGRAM: if (default_protocol_dgram(protocol)) return SECCLASS_UDP_SOCKET; + else if (extsockclass && protocol == IPPROTO_ICMP) + return SECCLASS_ICMP_SOCKET; else return SECCLASS_RAWIP_SOCKET; case SOCK_DCCP: @@ -1342,6 +1349,72 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc return SECCLASS_APPLETALK_SOCKET; } + if (extsockclass) { + switch (family) { + case PF_AX25: + return SECCLASS_AX25_SOCKET; + case PF_IPX: + return SECCLASS_IPX_SOCKET; + case PF_NETROM: + return SECCLASS_NETROM_SOCKET; + case PF_BRIDGE: + return SECCLASS_BRIDGE_SOCKET; + case PF_ATMPVC: + return SECCLASS_ATMPVC_SOCKET; + case PF_X25: + return SECCLASS_X25_SOCKET; + case PF_ROSE: + return SECCLASS_ROSE_SOCKET; + case PF_DECnet: + return SECCLASS_DECNET_SOCKET; + case PF_ATMSVC: + return SECCLASS_ATMSVC_SOCKET; + case PF_RDS: + return SECCLASS_RDS_SOCKET; + case PF_IRDA: + return SECCLASS_IRDA_SOCKET; + case PF_PPPOX: + return SECCLASS_PPPOX_SOCKET; + case PF_LLC: + return SECCLASS_LLC_SOCKET; + case PF_IB: + return SECCLASS_IB_SOCKET; + case PF_MPLS: + return SECCLASS_MPLS_SOCKET; + case PF_CAN: + return SECCLASS_CAN_SOCKET; + case PF_TIPC: + return SECCLASS_TIPC_SOCKET; + case PF_BLUETOOTH: + return SECCLASS_BLUETOOTH_SOCKET; + case PF_IUCV: + return SECCLASS_IUCV_SOCKET; + case PF_RXRPC: + return SECCLASS_RXRPC_SOCKET; + case PF_ISDN: + return SECCLASS_ISDN_SOCKET; + case PF_PHONET: + return SECCLASS_PHONET_SOCKET; + case PF_IEEE802154: + return SECCLASS_IEEE802154_SOCKET; + case PF_CAIF: + return SECCLASS_CAIF_SOCKET; + case PF_ALG: + return SECCLASS_ALG_SOCKET; + case PF_NFC: + return SECCLASS_NFC_SOCKET; + case PF_VSOCK: + return SECCLASS_VSOCK_SOCKET; + case PF_KCM: + return SECCLASS_KCM_SOCKET; + case PF_QIPCRTR: + return SECCLASS_QIPCRTR_SOCKET; +#if PF_MAX > 43 +#error New address family defined, please update this function. +#endif + } + } + return SECCLASS_SOCKET; } diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 13ae49b0baa0..0dfd26d0b8d8 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -171,5 +171,73 @@ struct security_class_mapping secclass_map[] = { { COMMON_CAP_PERMS, NULL } }, { "cap2_userns", { COMMON_CAP2_PERMS, NULL } }, + { "sctp_socket", + { COMMON_SOCK_PERMS, + "node_bind", NULL } }, + { "icmp_socket", + { COMMON_SOCK_PERMS, + "node_bind", NULL } }, + { "ax25_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "ipx_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "netrom_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "bridge_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "atmpvc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "x25_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "rose_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "decnet_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "atmsvc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "rds_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "irda_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "pppox_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "llc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "ib_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "mpls_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "can_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "tipc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "bluetooth_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "iucv_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "rxrpc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "isdn_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "phonet_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "ieee802154_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "caif_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "alg_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "nfc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "vsock_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "kcm_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "qipcrtr_socket", + { COMMON_SOCK_PERMS, NULL } }, { NULL } }; + +#if PF_MAX > 43 +#error New address family defined, please update secclass_map. +#endif diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 308a286c6cbe..beaa14b8b6cf 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -69,7 +69,7 @@ extern int selinux_enabled; enum { POLICYDB_CAPABILITY_NETPEER, POLICYDB_CAPABILITY_OPENPERM, - POLICYDB_CAPABILITY_REDHAT1, + POLICYDB_CAPABILITY_EXTSOCKCLASS, POLICYDB_CAPABILITY_ALWAYSNETWORK, __POLICYDB_CAPABILITY_MAX }; @@ -77,6 +77,7 @@ enum { extern int selinux_policycap_netpeer; extern int selinux_policycap_openperm; +extern int selinux_policycap_extsockclass; extern int selinux_policycap_alwaysnetwork; /* diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index cf9293e01fc1..0aac402a0f11 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -45,7 +45,7 @@ static char *policycap_names[] = { "network_peer_controls", "open_perms", - "redhat1", + "extended_socket_class", "always_check_network" }; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 082b20c78363..a70fcee9824b 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -72,6 +72,7 @@ int selinux_policycap_netpeer; int selinux_policycap_openperm; +int selinux_policycap_extsockclass; int selinux_policycap_alwaysnetwork; static DEFINE_RWLOCK(policy_rwlock); @@ -1988,6 +1989,8 @@ static void security_load_policycaps(void) POLICYDB_CAPABILITY_NETPEER); selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, POLICYDB_CAPABILITY_OPENPERM); + selinux_policycap_extsockclass = ebitmap_get_bit(&policydb.policycaps, + POLICYDB_CAPABILITY_EXTSOCKCLASS); selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps, POLICYDB_CAPABILITY_ALWAYSNETWORK); } From a2c7c6fbe5ab48f6e4ed22f4649c76d1efbfe643 Mon Sep 17 00:00:00 2001 From: Yongqin Liu Date: Mon, 9 Jan 2017 10:07:30 -0500 Subject: [PATCH 0278/1587] selinux: add security in-core xattr support for tracefs Since kernel 4.1 ftrace is supported as a new separate filesystem. It gets automatically mounted by the kernel under the old path /sys/kernel/debug/tracing. Because it lives now on a separate filesystem SELinux needs to be updated to also support setting SELinux labels on tracefs inodes. This is required for compatibility in Android when moving to Linux 4.1 or newer. Signed-off-by: Yongqin Liu Signed-off-by: William Roberts Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 74cd3a689cf8..5ce633aabce6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -492,6 +492,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) !strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "pstore") || !strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "rootfs"); } From ef37979a2cfa3905adbf0c2a681ce16c0aaea92d Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 9 Jan 2017 10:07:31 -0500 Subject: [PATCH 0279/1587] selinux: handle ICMPv6 consistently with ICMP commit 79c8b348f215 ("selinux: support distinctions among all network address families") mapped datagram ICMP sockets to the new icmp_socket security class, but left ICMPv6 sockets unchanged. This change fixes that oversight to handle both kinds of sockets consistently. Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5ce633aabce6..e4b953f760dd 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1295,7 +1295,8 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc case SOCK_DGRAM: if (default_protocol_dgram(protocol)) return SECCLASS_UDP_SOCKET; - else if (extsockclass && protocol == IPPROTO_ICMP) + else if (extsockclass && (protocol == IPPROTO_ICMP || + protocol == IPPROTO_ICMPV6)) return SECCLASS_ICMP_SOCKET; else return SECCLASS_RAWIP_SOCKET; From 01593d3299a1cfdb5e08acf95f63ec59dd674906 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 9 Jan 2017 10:07:31 -0500 Subject: [PATCH 0280/1587] selinux: allow context mounts on tmpfs, ramfs, devpts within user namespaces commit aad82892af261b9903cc11c55be3ecf5f0b0b4f8 ("selinux: Add support for unprivileged mounts from user namespaces") prohibited any use of context mount options within non-init user namespaces. However, this breaks use of context mount options for tmpfs mounts within user namespaces, which are being used by Docker/runc. There is no reason to block such usage for tmpfs, ramfs or devpts. Exempt these filesystem types from this restriction. Before: sh$ userns_child_exec -p -m -U -M '0 1000 1' -G '0 1000 1' bash sh# mount -t tmpfs -o context=system_u:object_r:user_tmp_t:s0:c13 none /tmp mount: tmpfs is write-protected, mounting read-only mount: cannot mount tmpfs read-only After: sh$ userns_child_exec -p -m -U -M '0 1000 1' -G '0 1000 1' bash sh# mount -t tmpfs -o context=system_u:object_r:user_tmp_t:s0:c13 none /tmp sh# ls -Zd /tmp unconfined_u:object_r:user_tmp_t:s0:c13 /tmp Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e4b953f760dd..e32f4b5f23a5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -834,10 +834,14 @@ static int selinux_set_mnt_opts(struct super_block *sb, } /* - * If this is a user namespace mount, no contexts are allowed - * on the command line and security labels must be ignored. + * If this is a user namespace mount and the filesystem type is not + * explicitly whitelisted, then no contexts are allowed on the command + * line and security labels must be ignored. */ - if (sb->s_user_ns != &init_user_ns) { + if (sb->s_user_ns != &init_user_ns && + strcmp(sb->s_type->name, "tmpfs") && + strcmp(sb->s_type->name, "ramfs") && + strcmp(sb->s_type->name, "devpts")) { if (context_sid || fscontext_sid || rootcontext_sid || defcontext_sid) { rc = -EACCES; From be0554c9bf9f7cc96f5205df8f8bd3573b74320e Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 9 Jan 2017 10:07:31 -0500 Subject: [PATCH 0281/1587] selinux: clean up cred usage and simplify SELinux was sometimes using the task "objective" credentials when it could/should use the "subjective" credentials. This was sometimes hidden by the fact that we were unnecessarily passing around pointers to the current task, making it appear as if the task could be something other than current, so eliminate all such passing of current. Inline various permission checking helper functions that can be reduced to a single avc_has_perm() call. Since the credentials infrastructure only allows a task to alter its own credentials, we can always assume that current must be the same as the target task in selinux_setprocattr after the check. We likely should move this check from selinux_setprocattr() to proc_pid_attr_write() and drop the task argument to the security hook altogether; it can only serve to confuse things. Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 298 ++++++++++++------------------ security/selinux/include/objsec.h | 10 + security/selinux/selinuxfs.c | 73 ++++---- 3 files changed, 168 insertions(+), 213 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e32f4b5f23a5..262e108c36d4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -210,16 +210,6 @@ static inline u32 task_sid(const struct task_struct *task) return sid; } -/* - * get the subjective security ID of the current task - */ -static inline u32 current_sid(void) -{ - const struct task_security_struct *tsec = current_security(); - - return tsec->sid; -} - /* Allocate and free functions for each kind of security blob. */ static int inode_alloc_security(struct inode *inode) @@ -1687,55 +1677,6 @@ static inline u32 signal_to_av(int sig) return perm; } -/* - * Check permission between a pair of credentials - * fork check, ptrace check, etc. - */ -static int cred_has_perm(const struct cred *actor, - const struct cred *target, - u32 perms) -{ - u32 asid = cred_sid(actor), tsid = cred_sid(target); - - return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL); -} - -/* - * Check permission between a pair of tasks, e.g. signal checks, - * fork check, ptrace check, etc. - * tsk1 is the actor and tsk2 is the target - * - this uses the default subjective creds of tsk1 - */ -static int task_has_perm(const struct task_struct *tsk1, - const struct task_struct *tsk2, - u32 perms) -{ - const struct task_security_struct *__tsec1, *__tsec2; - u32 sid1, sid2; - - rcu_read_lock(); - __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid; - __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid; - rcu_read_unlock(); - return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL); -} - -/* - * Check permission between current and another task, e.g. signal checks, - * fork check, ptrace check, etc. - * current is the actor and tsk2 is the target - * - this uses current's subjective creds - */ -static int current_has_perm(const struct task_struct *tsk, - u32 perms) -{ - u32 sid, tsid; - - sid = current_sid(); - tsid = task_sid(tsk); - return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL); -} - #if CAP_LAST_CAP > 63 #error Fix SELinux to handle capabilities > 63. #endif @@ -1777,16 +1718,6 @@ static int cred_has_capability(const struct cred *cred, return rc; } -/* Check whether a task is allowed to use a system operation. */ -static int task_has_system(struct task_struct *tsk, - u32 perms) -{ - u32 sid = task_sid(tsk); - - return avc_has_perm(sid, SECINITSID_KERNEL, - SECCLASS_SYSTEM, perms, NULL); -} - /* Check whether a task has a particular permission to an inode. The 'adp' parameter is optional and allows other audit data to be passed (e.g. the dentry). */ @@ -1958,15 +1889,6 @@ static int may_create(struct inode *dir, FILESYSTEM__ASSOCIATE, &ad); } -/* Check whether a task can create a key. */ -static int may_create_key(u32 ksid, - struct task_struct *ctx) -{ - u32 sid = task_sid(ctx); - - return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); -} - #define MAY_LINK 0 #define MAY_UNLINK 1 #define MAY_RMDIR 2 @@ -2222,24 +2144,26 @@ static int selinux_binder_transfer_file(struct task_struct *from, static int selinux_ptrace_access_check(struct task_struct *child, unsigned int mode) { - if (mode & PTRACE_MODE_READ) { - u32 sid = current_sid(); - u32 csid = task_sid(child); - return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); - } + u32 sid = current_sid(); + u32 csid = task_sid(child); - return current_has_perm(child, PROCESS__PTRACE); + if (mode & PTRACE_MODE_READ) + return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); + + return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); } static int selinux_ptrace_traceme(struct task_struct *parent) { - return task_has_perm(parent, current, PROCESS__PTRACE); + return avc_has_perm(task_sid(parent), current_sid(), SECCLASS_PROCESS, + PROCESS__PTRACE, NULL); } static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - return current_has_perm(target, PROCESS__GETCAP); + return avc_has_perm(current_sid(), task_sid(target), SECCLASS_PROCESS, + PROCESS__GETCAP, NULL); } static int selinux_capset(struct cred *new, const struct cred *old, @@ -2247,7 +2171,8 @@ static int selinux_capset(struct cred *new, const struct cred *old, const kernel_cap_t *inheritable, const kernel_cap_t *permitted) { - return cred_has_perm(old, new, PROCESS__SETCAP); + return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS, + PROCESS__SETCAP, NULL); } /* @@ -2303,29 +2228,22 @@ static int selinux_quota_on(struct dentry *dentry) static int selinux_syslog(int type) { - int rc; - switch (type) { case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ - rc = task_has_system(current, SYSTEM__SYSLOG_READ); - break; + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL); case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ /* Set level of messages printed to console */ case SYSLOG_ACTION_CONSOLE_LEVEL: - rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); - break; - case SYSLOG_ACTION_CLOSE: /* Close log */ - case SYSLOG_ACTION_OPEN: /* Open log */ - case SYSLOG_ACTION_READ: /* Read from log */ - case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */ - case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */ - default: - rc = task_has_system(current, SYSTEM__SYSLOG_MOD); - break; + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, + NULL); } - return rc; + /* All other syslog types */ + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL); } /* @@ -2350,13 +2268,13 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) /* binprm security operations */ -static u32 ptrace_parent_sid(struct task_struct *task) +static u32 ptrace_parent_sid(void) { u32 sid = 0; struct task_struct *tracer; rcu_read_lock(); - tracer = ptrace_parent(task); + tracer = ptrace_parent(current); if (tracer) sid = task_sid(tracer); rcu_read_unlock(); @@ -2485,7 +2403,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) * changes its SID has the appropriate permit */ if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { - u32 ptsid = ptrace_parent_sid(current); + u32 ptsid = ptrace_parent_sid(); if (ptsid != 0) { rc = avc_has_perm(ptsid, new_tsec->sid, SECCLASS_PROCESS, @@ -3582,6 +3500,7 @@ static int default_noexec; static int file_map_prot_check(struct file *file, unsigned long prot, int shared) { const struct cred *cred = current_cred(); + u32 sid = cred_sid(cred); int rc = 0; if (default_noexec && @@ -3592,7 +3511,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared * private file mapping that will also be writable. * This has an additional check. */ - rc = cred_has_perm(cred, cred, PROCESS__EXECMEM); + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, + PROCESS__EXECMEM, NULL); if (rc) goto error; } @@ -3643,6 +3563,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, unsigned long prot) { const struct cred *cred = current_cred(); + u32 sid = cred_sid(cred); if (selinux_checkreqprot) prot = reqprot; @@ -3652,12 +3573,14 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, int rc = 0; if (vma->vm_start >= vma->vm_mm->start_brk && vma->vm_end <= vma->vm_mm->brk) { - rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, + PROCESS__EXECHEAP, NULL); } else if (!vma->vm_file && ((vma->vm_start <= vma->vm_mm->start_stack && vma->vm_end >= vma->vm_mm->start_stack) || vma_is_stack_for_current(vma))) { - rc = current_has_perm(current, PROCESS__EXECSTACK); + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, + PROCESS__EXECSTACK, NULL); } else if (vma->vm_file && vma->anon_vma) { /* * We are making executable a file mapping that has @@ -3790,7 +3713,9 @@ static int selinux_file_open(struct file *file, const struct cred *cred) static int selinux_task_create(unsigned long clone_flags) { - return current_has_perm(current, PROCESS__FORK); + u32 sid = current_sid(); + + return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL); } /* @@ -3900,15 +3825,12 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) static int selinux_kernel_module_request(char *kmod_name) { - u32 sid; struct common_audit_data ad; - sid = task_sid(current); - ad.type = LSM_AUDIT_DATA_KMOD; ad.u.kmod_name = kmod_name; - return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, &ad); } @@ -3960,17 +3882,20 @@ static int selinux_kernel_read_file(struct file *file, static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) { - return current_has_perm(p, PROCESS__SETPGID); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETPGID, NULL); } static int selinux_task_getpgid(struct task_struct *p) { - return current_has_perm(p, PROCESS__GETPGID); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__GETPGID, NULL); } static int selinux_task_getsid(struct task_struct *p) { - return current_has_perm(p, PROCESS__GETSESSION); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__GETSESSION, NULL); } static void selinux_task_getsecid(struct task_struct *p, u32 *secid) @@ -3980,17 +3905,20 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid) static int selinux_task_setnice(struct task_struct *p, int nice) { - return current_has_perm(p, PROCESS__SETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETSCHED, NULL); } static int selinux_task_setioprio(struct task_struct *p, int ioprio) { - return current_has_perm(p, PROCESS__SETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETSCHED, NULL); } static int selinux_task_getioprio(struct task_struct *p) { - return current_has_perm(p, PROCESS__GETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__GETSCHED, NULL); } static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, @@ -4003,47 +3931,48 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, later be used as a safe reset point for the soft limit upon context transitions. See selinux_bprm_committing_creds. */ if (old_rlim->rlim_max != new_rlim->rlim_max) - return current_has_perm(p, PROCESS__SETRLIMIT); + return avc_has_perm(current_sid(), task_sid(p), + SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL); return 0; } static int selinux_task_setscheduler(struct task_struct *p) { - return current_has_perm(p, PROCESS__SETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETSCHED, NULL); } static int selinux_task_getscheduler(struct task_struct *p) { - return current_has_perm(p, PROCESS__GETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__GETSCHED, NULL); } static int selinux_task_movememory(struct task_struct *p) { - return current_has_perm(p, PROCESS__SETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETSCHED, NULL); } static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid) { u32 perm; - int rc; if (!sig) perm = PROCESS__SIGNULL; /* null signal; existence test */ else perm = signal_to_av(sig); - if (secid) - rc = avc_has_perm(secid, task_sid(p), - SECCLASS_PROCESS, perm, NULL); - else - rc = current_has_perm(p, perm); - return rc; + if (!secid) + secid = current_sid(); + return avc_has_perm(secid, task_sid(p), SECCLASS_PROCESS, perm, NULL); } static int selinux_task_wait(struct task_struct *p) { - return task_has_perm(p, current, PROCESS__SIGCHLD); + return avc_has_perm(task_sid(p), current_sid(), SECCLASS_PROCESS, + PROCESS__SIGCHLD, NULL); } static void selinux_task_to_inode(struct task_struct *p, @@ -4333,12 +4262,11 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec, socksid); } -static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) +static int sock_has_perm(struct sock *sk, u32 perms) { struct sk_security_struct *sksec = sk->sk_security; struct common_audit_data ad; struct lsm_network_audit net = {0,}; - u32 tsid = task_sid(task); if (sksec->sid == SECINITSID_KERNEL) return 0; @@ -4347,7 +4275,8 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) ad.u.net = &net; ad.u.net->sk = sk; - return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad); + return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms, + &ad); } static int selinux_socket_create(int family, int type, @@ -4409,7 +4338,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in u16 family; int err; - err = sock_has_perm(current, sk, SOCKET__BIND); + err = sock_has_perm(sk, SOCKET__BIND); if (err) goto out; @@ -4508,7 +4437,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, struct sk_security_struct *sksec = sk->sk_security; int err; - err = sock_has_perm(current, sk, SOCKET__CONNECT); + err = sock_has_perm(sk, SOCKET__CONNECT); if (err) return err; @@ -4560,7 +4489,7 @@ out: static int selinux_socket_listen(struct socket *sock, int backlog) { - return sock_has_perm(current, sock->sk, SOCKET__LISTEN); + return sock_has_perm(sock->sk, SOCKET__LISTEN); } static int selinux_socket_accept(struct socket *sock, struct socket *newsock) @@ -4571,7 +4500,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) u16 sclass; u32 sid; - err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT); + err = sock_has_perm(sock->sk, SOCKET__ACCEPT); if (err) return err; @@ -4592,30 +4521,30 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { - return sock_has_perm(current, sock->sk, SOCKET__WRITE); + return sock_has_perm(sock->sk, SOCKET__WRITE); } static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags) { - return sock_has_perm(current, sock->sk, SOCKET__READ); + return sock_has_perm(sock->sk, SOCKET__READ); } static int selinux_socket_getsockname(struct socket *sock) { - return sock_has_perm(current, sock->sk, SOCKET__GETATTR); + return sock_has_perm(sock->sk, SOCKET__GETATTR); } static int selinux_socket_getpeername(struct socket *sock) { - return sock_has_perm(current, sock->sk, SOCKET__GETATTR); + return sock_has_perm(sock->sk, SOCKET__GETATTR); } static int selinux_socket_setsockopt(struct socket *sock, int level, int optname) { int err; - err = sock_has_perm(current, sock->sk, SOCKET__SETOPT); + err = sock_has_perm(sock->sk, SOCKET__SETOPT); if (err) return err; @@ -4625,12 +4554,12 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname static int selinux_socket_getsockopt(struct socket *sock, int level, int optname) { - return sock_has_perm(current, sock->sk, SOCKET__GETOPT); + return sock_has_perm(sock->sk, SOCKET__GETOPT); } static int selinux_socket_shutdown(struct socket *sock, int how) { - return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN); + return sock_has_perm(sock->sk, SOCKET__SHUTDOWN); } static int selinux_socket_unix_stream_connect(struct sock *sock, @@ -5118,7 +5047,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) goto out; } - err = sock_has_perm(current, sk, perm); + err = sock_has_perm(sk, perm); out: return err; } @@ -5449,20 +5378,17 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) return selinux_nlmsg_perm(sk, skb); } -static int ipc_alloc_security(struct task_struct *task, - struct kern_ipc_perm *perm, +static int ipc_alloc_security(struct kern_ipc_perm *perm, u16 sclass) { struct ipc_security_struct *isec; - u32 sid; isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL); if (!isec) return -ENOMEM; - sid = task_sid(task); isec->sclass = sclass; - isec->sid = sid; + isec->sid = current_sid(); perm->security = isec; return 0; @@ -5530,7 +5456,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) u32 sid = current_sid(); int rc; - rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ); + rc = ipc_alloc_security(&msq->q_perm, SECCLASS_MSGQ); if (rc) return rc; @@ -5577,7 +5503,8 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd) case IPC_INFO: case MSG_INFO: /* No specific object, just general system-wide information. */ - return task_has_system(current, SYSTEM__IPC_INFO); + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case IPC_STAT: case MSG_STAT: perms = MSGQ__GETATTR | MSGQ__ASSOCIATE; @@ -5671,7 +5598,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) u32 sid = current_sid(); int rc; - rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM); + rc = ipc_alloc_security(&shp->shm_perm, SECCLASS_SHM); if (rc) return rc; @@ -5719,7 +5646,8 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd) case IPC_INFO: case SHM_INFO: /* No specific object, just general system-wide information. */ - return task_has_system(current, SYSTEM__IPC_INFO); + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case IPC_STAT: case SHM_STAT: perms = SHM__GETATTR | SHM__ASSOCIATE; @@ -5763,7 +5691,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) u32 sid = current_sid(); int rc; - rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM); + rc = ipc_alloc_security(&sma->sem_perm, SECCLASS_SEM); if (rc) return rc; @@ -5811,7 +5739,8 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd) case IPC_INFO: case SEM_INFO: /* No specific object, just general system-wide information. */ - return task_has_system(current, SYSTEM__IPC_INFO); + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case GETPID: case GETNCNT: case GETZCNT: @@ -5892,15 +5821,16 @@ static int selinux_getprocattr(struct task_struct *p, int error; unsigned len; - if (current != p) { - error = current_has_perm(p, PROCESS__GETATTR); - if (error) - return error; - } - rcu_read_lock(); __tsec = __task_cred(p)->security; + if (current != p) { + error = avc_has_perm(current_sid(), __tsec->sid, + SECCLASS_PROCESS, PROCESS__GETATTR, NULL); + if (error) + goto bad; + } + if (!strcmp(name, "current")) sid = __tsec->sid; else if (!strcmp(name, "prev")) @@ -5913,8 +5843,10 @@ static int selinux_getprocattr(struct task_struct *p, sid = __tsec->keycreate_sid; else if (!strcmp(name, "sockcreate")) sid = __tsec->sockcreate_sid; - else - goto invalid; + else { + error = -EINVAL; + goto bad; + } rcu_read_unlock(); if (!sid) @@ -5925,9 +5857,9 @@ static int selinux_getprocattr(struct task_struct *p, return error; return len; -invalid: +bad: rcu_read_unlock(); - return -EINVAL; + return error; } static int selinux_setprocattr(struct task_struct *p, @@ -5935,31 +5867,38 @@ static int selinux_setprocattr(struct task_struct *p, { struct task_security_struct *tsec; struct cred *new; - u32 sid = 0, ptsid; + u32 mysid = current_sid(), sid = 0, ptsid; int error; char *str = value; if (current != p) { - /* SELinux only allows a process to change its own - security attributes. */ + /* + * A task may only alter its own credentials. + * SELinux has always enforced this restriction, + * and it is now mandated by the Linux credentials + * infrastructure; see Documentation/security/credentials.txt. + */ return -EACCES; } /* * Basic control over ability to set these attributes at all. - * current == p, but we'll pass them separately in case the - * above restriction is ever removed. */ if (!strcmp(name, "exec")) - error = current_has_perm(p, PROCESS__SETEXEC); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETEXEC, NULL); else if (!strcmp(name, "fscreate")) - error = current_has_perm(p, PROCESS__SETFSCREATE); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETFSCREATE, NULL); else if (!strcmp(name, "keycreate")) - error = current_has_perm(p, PROCESS__SETKEYCREATE); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETKEYCREATE, NULL); else if (!strcmp(name, "sockcreate")) - error = current_has_perm(p, PROCESS__SETSOCKCREATE); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETSOCKCREATE, NULL); else if (!strcmp(name, "current")) - error = current_has_perm(p, PROCESS__SETCURRENT); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETCURRENT, NULL); else error = -EINVAL; if (error) @@ -6013,7 +5952,8 @@ static int selinux_setprocattr(struct task_struct *p, } else if (!strcmp(name, "fscreate")) { tsec->create_sid = sid; } else if (!strcmp(name, "keycreate")) { - error = may_create_key(sid, p); + error = avc_has_perm(mysid, sid, SECCLASS_KEY, KEY__CREATE, + NULL); if (error) goto abort_change; tsec->keycreate_sid = sid; @@ -6040,7 +5980,7 @@ static int selinux_setprocattr(struct task_struct *p, /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and fail. */ - ptsid = ptrace_parent_sid(p); + ptsid = ptrace_parent_sid(); if (ptsid != 0) { error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index e8dab0f02c72..c03cdcd12a3b 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -37,6 +37,16 @@ struct task_security_struct { u32 sockcreate_sid; /* fscreate SID */ }; +/* + * get the subjective security ID of the current task + */ +static inline u32 current_sid(void) +{ + const struct task_security_struct *tsec = current_security(); + + return tsec->sid; +} + enum label_initialized { LABEL_INVALID, /* invalid or not initialized */ LABEL_INITIALIZED, /* initialized */ diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 0aac402a0f11..55345f84f17d 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -77,25 +77,6 @@ static char policy_opened; /* global data for policy capabilities */ static struct dentry *policycap_dir; -/* Check whether a task is allowed to use a security operation. */ -static int task_has_security(struct task_struct *tsk, - u32 perms) -{ - const struct task_security_struct *tsec; - u32 sid = 0; - - rcu_read_lock(); - tsec = __task_cred(tsk)->security; - if (tsec) - sid = tsec->sid; - rcu_read_unlock(); - if (!tsec) - return -EACCES; - - return avc_has_perm(sid, SECINITSID_SECURITY, - SECCLASS_SECURITY, perms, NULL); -} - enum sel_inos { SEL_ROOT_INO = 2, SEL_LOAD, /* load policy */ @@ -166,7 +147,9 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, new_value = !!new_value; if (new_value != selinux_enforcing) { - length = task_has_security(current, SECURITY__SETENFORCE); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETENFORCE, + NULL); if (length) goto out; audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, @@ -368,7 +351,8 @@ static int sel_open_policy(struct inode *inode, struct file *filp) mutex_lock(&sel_mutex); - rc = task_has_security(current, SECURITY__READ_POLICY); + rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); if (rc) goto err; @@ -429,7 +413,8 @@ static ssize_t sel_read_policy(struct file *filp, char __user *buf, mutex_lock(&sel_mutex); - ret = task_has_security(current, SECURITY__READ_POLICY); + ret = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); if (ret) goto out; @@ -499,7 +484,8 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, mutex_lock(&sel_mutex); - length = task_has_security(current, SECURITY__LOAD_POLICY); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL); if (length) goto out; @@ -561,7 +547,8 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size) u32 sid, len; ssize_t length; - length = task_has_security(current, SECURITY__CHECK_CONTEXT); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL); if (length) goto out; @@ -604,7 +591,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, ssize_t length; unsigned int new_value; - length = task_has_security(current, SECURITY__SETCHECKREQPROT); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT, + NULL); if (length) return length; @@ -645,7 +634,8 @@ static ssize_t sel_write_validatetrans(struct file *file, u16 tclass; int rc; - rc = task_has_security(current, SECURITY__VALIDATE_TRANS); + rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL); if (rc) goto out; @@ -772,7 +762,8 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) struct av_decision avd; ssize_t length; - length = task_has_security(current, SECURITY__COMPUTE_AV); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL); if (length) goto out; @@ -822,7 +813,9 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) u32 len; int nargs; - length = task_has_security(current, SECURITY__COMPUTE_CREATE); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, + NULL); if (length) goto out; @@ -919,7 +912,9 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) char *newcon = NULL; u32 len; - length = task_has_security(current, SECURITY__COMPUTE_RELABEL); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, + NULL); if (length) goto out; @@ -975,7 +970,9 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) int i, rc; u32 len, nsids; - length = task_has_security(current, SECURITY__COMPUTE_USER); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_USER, + NULL); if (length) goto out; @@ -1035,7 +1032,9 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) char *newcon = NULL; u32 len; - length = task_has_security(current, SECURITY__COMPUTE_MEMBER); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, + NULL); if (length) goto out; @@ -1142,7 +1141,9 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, mutex_lock(&sel_mutex); - length = task_has_security(current, SECURITY__SETBOOL); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETBOOL, + NULL); if (length) goto out; @@ -1198,7 +1199,9 @@ static ssize_t sel_commit_bools_write(struct file *filep, mutex_lock(&sel_mutex); - length = task_has_security(current, SECURITY__SETBOOL); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETBOOL, + NULL); if (length) goto out; @@ -1351,7 +1354,9 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, ssize_t ret; unsigned int new_value; - ret = task_has_security(current, SECURITY__SETSECPARAM); + ret = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETSECPARAM, + NULL); if (ret) return ret; From b21507e272627c434e8dd74e8d51fd8245281b59 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 9 Jan 2017 10:07:31 -0500 Subject: [PATCH 0282/1587] proc,security: move restriction on writing /proc/pid/attr nodes to proc Processes can only alter their own security attributes via /proc/pid/attr nodes. This is presently enforced by each individual security module and is also imposed by the Linux credentials implementation, which only allows a task to alter its own credentials. Move the check enforcing this restriction from the individual security modules to proc_pid_attr_write() before calling the security hook, and drop the unnecessary task argument to the security hook since it can only ever be the current task. Signed-off-by: Stephen Smalley Acked-by: Casey Schaufler Acked-by: John Johansen Signed-off-by: Paul Moore --- fs/proc/base.c | 13 +++++++++---- include/linux/lsm_hooks.h | 3 +-- include/linux/security.h | 4 ++-- security/apparmor/lsm.c | 7 ++----- security/security.c | 4 ++-- security/selinux/hooks.c | 13 +------------ security/smack/smack_lsm.c | 11 +---------- 7 files changed, 18 insertions(+), 37 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 8e7e61b28f31..988c5a77e888 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2488,6 +2488,12 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, length = -ESRCH; if (!task) goto out_no_task; + + /* A task may only write its own attributes. */ + length = -EACCES; + if (current != task) + goto out; + if (count > PAGE_SIZE) count = PAGE_SIZE; @@ -2503,14 +2509,13 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, } /* Guard against adverse ptrace interaction */ - length = mutex_lock_interruptible(&task->signal->cred_guard_mutex); + length = mutex_lock_interruptible(¤t->signal->cred_guard_mutex); if (length < 0) goto out_free; - length = security_setprocattr(task, - (char*)file->f_path.dentry->d_name.name, + length = security_setprocattr(file->f_path.dentry->d_name.name, page, count); - mutex_unlock(&task->signal->cred_guard_mutex); + mutex_unlock(¤t->signal->cred_guard_mutex); out_free: kfree(page); out: diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 558adfa5c8a8..0dde95900196 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1547,8 +1547,7 @@ union security_list_options { void (*d_instantiate)(struct dentry *dentry, struct inode *inode); int (*getprocattr)(struct task_struct *p, char *name, char **value); - int (*setprocattr)(struct task_struct *p, char *name, void *value, - size_t size); + int (*setprocattr)(const char *name, void *value, size_t size); int (*ismaclabel)(const char *name); int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen); int (*secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid); diff --git a/include/linux/security.h b/include/linux/security.h index c2125e9093e8..f4ebac117fa6 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -361,7 +361,7 @@ int security_sem_semop(struct sem_array *sma, struct sembuf *sops, unsigned nsops, int alter); void security_d_instantiate(struct dentry *dentry, struct inode *inode); int security_getprocattr(struct task_struct *p, char *name, char **value); -int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size); +int security_setprocattr(const char *name, void *value, size_t size); int security_netlink_send(struct sock *sk, struct sk_buff *skb); int security_ismaclabel(const char *name); int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); @@ -1106,7 +1106,7 @@ static inline int security_getprocattr(struct task_struct *p, char *name, char * return -EINVAL; } -static inline int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size) +static inline int security_setprocattr(char *name, void *value, size_t size) { return -EINVAL; } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 41b8cb115801..8202e5583479 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -495,8 +495,8 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, return error; } -static int apparmor_setprocattr(struct task_struct *task, char *name, - void *value, size_t size) +static int apparmor_setprocattr(const char *name, void *value, + size_t size) { struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; @@ -506,9 +506,6 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, if (size == 0) return -EINVAL; - /* task can only write its own attributes */ - if (current != task) - return -EACCES; /* AppArmor requires that the buffer must be null terminated atm */ if (args[size - 1] != '\0') { diff --git a/security/security.c b/security/security.c index f825304f04a7..32052f5c76b2 100644 --- a/security/security.c +++ b/security/security.c @@ -1170,9 +1170,9 @@ int security_getprocattr(struct task_struct *p, char *name, char **value) return call_int_hook(getprocattr, -EINVAL, p, name, value); } -int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size) +int security_setprocattr(const char *name, void *value, size_t size) { - return call_int_hook(setprocattr, -EINVAL, p, name, value, size); + return call_int_hook(setprocattr, -EINVAL, name, value, size); } int security_netlink_send(struct sock *sk, struct sk_buff *skb) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 262e108c36d4..bada3cd42b9c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5862,8 +5862,7 @@ bad: return error; } -static int selinux_setprocattr(struct task_struct *p, - char *name, void *value, size_t size) +static int selinux_setprocattr(const char *name, void *value, size_t size) { struct task_security_struct *tsec; struct cred *new; @@ -5871,16 +5870,6 @@ static int selinux_setprocattr(struct task_struct *p, int error; char *str = value; - if (current != p) { - /* - * A task may only alter its own credentials. - * SELinux has always enforced this restriction, - * and it is now mandated by the Linux credentials - * infrastructure; see Documentation/security/credentials.txt. - */ - return -EACCES; - } - /* * Basic control over ability to set these attributes at all. */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 94dc9d406ce3..8da4a6b9ca4d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3620,7 +3620,6 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) /** * smack_setprocattr - Smack process attribute setting - * @p: the object task * @name: the name of the attribute in /proc/.../attr * @value: the value to set * @size: the size of the value @@ -3630,8 +3629,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) * * Returns the length of the smack label or an error code */ -static int smack_setprocattr(struct task_struct *p, char *name, - void *value, size_t size) +static int smack_setprocattr(const char *name, void *value, size_t size) { struct task_smack *tsp = current_security(); struct cred *new; @@ -3639,13 +3637,6 @@ static int smack_setprocattr(struct task_struct *p, char *name, struct smack_known_list_elem *sklep; int rc; - /* - * Changing another process' Smack value is too dangerous - * and supports no sane use case. - */ - if (p != current) - return -EPERM; - if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel)) return -EPERM; From 4262fb51c9f53e0c623663216e6a5d1872a45824 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 9 Jan 2017 10:07:31 -0500 Subject: [PATCH 0283/1587] selinux: log errors when loading new policy Adds error logging to the code paths which can fail when loading a new policy in sel_write_load(). If the policy fails to be loaded from userspace then a warning message is printed, whereas if a failure occurs after loading policy from userspace an error message will be printed with details on where policy loading failed (recreating one of /classes/, /policy_capabilities/, /booleans/ in the SELinux fs). Also, if sel_make_bools() fails to obtain an SID for an entry in /booleans/* an error will be printed indicating the path of the boolean. Signed-off-by: Gary Tierney Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/selinuxfs.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 55345f84f17d..7672b61d6673 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -508,20 +508,28 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, goto out; length = security_load_policy(data, count); - if (length) + if (length) { + pr_warn_ratelimited("SELinux: failed to load policy\n"); goto out; + } length = sel_make_bools(); - if (length) + if (length) { + pr_err("SELinux: failed to load policy booleans\n"); goto out1; + } length = sel_make_classes(); - if (length) + if (length) { + pr_err("SELinux: failed to load policy classes\n"); goto out1; + } length = sel_make_policycap(); - if (length) + if (length) { + pr_err("SELinux: failed to load policy capabilities\n"); goto out1; + } length = count; @@ -1302,9 +1310,12 @@ static int sel_make_bools(void) isec = (struct inode_security_struct *)inode->i_security; ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); - if (ret) + if (ret) { + pr_err("SELinux: failed to lookup sid for %s\n", page); goto out; + } + isec->sid = sid; isec->initialized = LABEL_INITIALIZED; inode->i_fop = &sel_bool_ops; From 900fde06cb9d27625fec4f5cabd7f5462adc79fb Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 9 Jan 2017 10:07:32 -0500 Subject: [PATCH 0284/1587] selinux: default to security isid in sel_make_bools() if no sid is found Use SECINITSID_SECURITY as the default SID for booleans which don't have a matching SID returned from security_genfs_sid(), also update the error message to a warning which matches this. This prevents the policy failing to load (and consequently the system failing to boot) when there is no default genfscon statement matched for the selinuxfs in the new policy. Signed-off-by: Gary Tierney Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/selinuxfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 7672b61d6673..c354807381c1 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1311,9 +1311,9 @@ static int sel_make_bools(void) isec = (struct inode_security_struct *)inode->i_security; ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); if (ret) { - pr_err("SELinux: failed to lookup sid for %s\n", page); - goto out; - + pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n", + page); + sid = SECINITSID_SECURITY; } isec->sid = sid; From fb1b8b117531f217e7d332bdc5cbdf8ebb077ea5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Jan 2017 15:49:28 +0100 Subject: [PATCH 0285/1587] libata-eh: Use switch() instead of sparse array for protocol strings Replace the sparse 256-pointer array for looking up protocol strings by a switch() statement to reduce kernel size. According to bloat-o-meter, this saves 910 bytes on m68k (32-bit), and 1892 bytes on arm64 (64-bit). Signed-off-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/libata-eh.c | 44 +++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0e1ec37070d1..e7196fc29ff0 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2606,21 +2606,39 @@ static void ata_eh_link_report(struct ata_link *link) [DMA_TO_DEVICE] = "out", [DMA_FROM_DEVICE] = "in", }; - static const char *prot_str[] = { - [ATA_PROT_UNKNOWN] = "unknown", - [ATA_PROT_NODATA] = "nodata", - [ATA_PROT_PIO] = "pio", - [ATA_PROT_DMA] = "dma", - [ATA_PROT_NCQ] = "ncq dma", - [ATA_PROT_NCQ_NODATA] = "ncq nodata", - [ATAPI_PROT_NODATA] = "nodata", - [ATAPI_PROT_PIO] = "pio", - [ATAPI_PROT_DMA] = "dma", - }; + const char *prot_str = NULL; + switch (qc->tf.protocol) { + case ATA_PROT_UNKNOWN: + prot_str = "unknown"; + break; + case ATA_PROT_NODATA: + prot_str = "nodata"; + break; + case ATA_PROT_PIO: + prot_str = "pio"; + break; + case ATA_PROT_DMA: + prot_str = "dma"; + break; + case ATA_PROT_NCQ: + prot_str = "ncq dma"; + break; + case ATA_PROT_NCQ_NODATA: + prot_str = "ncq nodata"; + break; + case ATAPI_PROT_NODATA: + prot_str = "nodata"; + break; + case ATAPI_PROT_PIO: + prot_str = "pio"; + break; + case ATAPI_PROT_DMA: + prot_str = "dma"; + break; + } snprintf(data_buf, sizeof(data_buf), " %s %u %s", - prot_str[qc->tf.protocol], qc->nbytes, - dma_str[qc->dma_dir]); + prot_str, qc->nbytes, dma_str[qc->dma_dir]); } if (ata_is_atapi(qc->tf.protocol)) { From 92c2b671848e7816455ba5374e98913d920f3257 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 30 Dec 2016 10:37:31 -0800 Subject: [PATCH 0286/1587] pinctrl: core: Make dt_free_map optional If the pin controller driver is using devm_kzalloc, there may not be anything to do for dt_free_map. Let's make it optional to avoid unncessary boilerplate code. Signed-off-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 3 --- drivers/pinctrl/devicetree.c | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 9f305ac06275..5b1ab06d92c2 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1913,9 +1913,6 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev) !ops->get_group_name) return -EINVAL; - if (ops->dt_node_to_map && !ops->dt_free_map) - return -EINVAL; - return 0; } diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index e082bddad83a..0e5c9f14a706 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -42,7 +42,8 @@ static void dt_free_map(struct pinctrl_dev *pctldev, { if (pctldev) { const struct pinctrl_ops *ops = pctldev->desc->pctlops; - ops->dt_free_map(pctldev, map, num_maps); + if (ops->dt_free_map) + ops->dt_free_map(pctldev, map, num_maps); } else { /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */ kfree(map); From 003910ebc83bcac2ea543dbc6dfff2bc4fa67789 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 5 Jan 2017 10:54:14 -0800 Subject: [PATCH 0287/1587] pinctrl: Introduce TI IOdelay configuration driver SoC family such as DRA7 family of processors have, in addition to the regular muxing of pins (as done by pinctrl-single), a separate hardware module called IODelay which is also expected to be configured. The "IODelay" module has it's own register space that is independent of the control module and the padconf register area. With recent changes to the pinctrl framework, we can now support this hardware with a reasonably minimal driver by using #pinctrl-cells, GENERIC_PINCTRL_GROUPS and GENERIC_PINMUX_FUNCTIONS. It is advocated strongly in TI's official documentation considering the existing design of the DRA7 family of processors during mux or IODelay reconfiguration, there is a potential for a significant glitch which may cause functional impairment to certain hardware. It is hence recommended to do as little of muxing as absolutely necessary without I/O isolation (which can only be done in initial stages of bootloader). NOTE: with the system wide I/O isolation scheme present in DRA7 SoC family, it is not reasonable to do stop all I/O operations for every such pad configuration scheme. So, we will let it glitch when used in this mode. Even with the above limitation, certain functionality such as MMC has mandatory need for IODelay reconfiguration requirements, depending on speed of transfer. In these cases, with careful examination of usecase involved, the expected glitch can be controlled such that it does not impact functionality. In short, IODelay module support as a padconf driver being introduced here is not expected to do SoC wide I/O Isolation and is meant for a limited subset of IODelay configuration requirements that need to be dynamic and whose glitchy behavior will not cause functionality failure for that interface. IMPORTANT NOTE: we take the approach of keeping LOCK_BITs cleared to 0x0 at all times, even when configuring Manual IO Timing Modes. This is done by eliminating the LOCK_BIT=1 setting from Step of the Manual IO timing Mode configuration procedure. This option leaves the CFG_* registers unprotected from unintended writes to the CTRL_CORE_PAD_* registers while Manual IO Timing Modes are configured. This approach is taken to allow for a generic driver to exist in kernel world that has to be used carefully in required usecases. Signed-off-by: Nishanth Menon Signed-off-by: Lokesh Vutla [tony@atomide.com: updated to use generic pinctrl functions, added binding documentation, updated comments] Acked-by: Rob Herring Signed-off-by: Tony Lindgren Signed-off-by: Linus Walleij --- .../bindings/pinctrl/ti,iodelay.txt | 47 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/ti/Kconfig | 10 + drivers/pinctrl/ti/Makefile | 1 + drivers/pinctrl/ti/pinctrl-ti-iodelay.c | 944 ++++++++++++++++++ 6 files changed, 1004 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/ti,iodelay.txt create mode 100644 drivers/pinctrl/ti/Kconfig create mode 100644 drivers/pinctrl/ti/Makefile create mode 100644 drivers/pinctrl/ti/pinctrl-ti-iodelay.c diff --git a/Documentation/devicetree/bindings/pinctrl/ti,iodelay.txt b/Documentation/devicetree/bindings/pinctrl/ti,iodelay.txt new file mode 100644 index 000000000000..c3ed1232b6a3 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/ti,iodelay.txt @@ -0,0 +1,47 @@ +* Pin configuration for TI IODELAY controller + +TI dra7 based SoCs such as am57xx have a controller for setting the IO delay +for each pin. For most part the IO delay values are programmed by the bootloader, +but some pins need to be configured dynamically by the kernel such as the +MMC pins. + +Required Properties: + + - compatible: Must be "ti,dra7-iodelay" + - reg: Base address and length of the memory resource used + - #address-cells: Number of address cells + - #size-cells: Size of cells + - #pinctrl-cells: Number of pinctrl cells, must be 2. See also + Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example +------- + +In the SoC specific dtsi file: + + dra7_iodelay_core: padconf@4844a000 { + compatible = "ti,dra7-iodelay"; + reg = <0x4844a000 0x0d1c>; + #address-cells = <1>; + #size-cells = <0>; + #pinctrl-cells = <2>; + }; + +In board-specific file: + +&dra7_iodelay_core { + mmc2_iodelay_3v3_conf: mmc2_iodelay_3v3_conf { + pinctrl-pin-array = < + 0x18c A_DELAY_PS(0) G_DELAY_PS(120) /* CFG_GPMC_A19_IN */ + 0x1a4 A_DELAY_PS(265) G_DELAY_PS(360) /* CFG_GPMC_A20_IN */ + 0x1b0 A_DELAY_PS(0) G_DELAY_PS(120) /* CFG_GPMC_A21_IN */ + 0x1bc A_DELAY_PS(0) G_DELAY_PS(120) /* CFG_GPMC_A22_IN */ + 0x1c8 A_DELAY_PS(287) G_DELAY_PS(420) /* CFG_GPMC_A23_IN */ + 0x1d4 A_DELAY_PS(144) G_DELAY_PS(240) /* CFG_GPMC_A24_IN */ + 0x1e0 A_DELAY_PS(0) G_DELAY_PS(0) /* CFG_GPMC_A25_IN */ + 0x1ec A_DELAY_PS(120) G_DELAY_PS(0) /* CFG_GPMC_A26_IN */ + 0x1f8 A_DELAY_PS(120) G_DELAY_PS(180) /* CFG_GPMC_A27_IN */ + 0x360 A_DELAY_PS(0) G_DELAY_PS(0) /* CFG_GPMC_CS1_IN */ + >; + }; +}; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e806f96fc8a3..8f8c2af45781 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -300,6 +300,7 @@ source "drivers/pinctrl/spear/Kconfig" source "drivers/pinctrl/stm32/Kconfig" source "drivers/pinctrl/sunxi/Kconfig" source "drivers/pinctrl/tegra/Kconfig" +source "drivers/pinctrl/ti/Kconfig" source "drivers/pinctrl/uniphier/Kconfig" source "drivers/pinctrl/vt8500/Kconfig" source "drivers/pinctrl/mediatek/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 25d50a86981d..a251f439626f 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc/ obj-$(CONFIG_PINCTRL_SPEAR) += spear/ obj-$(CONFIG_PINCTRL_STM32) += stm32/ obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/ +obj-y += ti/ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_VT8500) += vt8500/ obj-$(CONFIG_PINCTRL_MTK) += mediatek/ diff --git a/drivers/pinctrl/ti/Kconfig b/drivers/pinctrl/ti/Kconfig new file mode 100644 index 000000000000..815a88673d38 --- /dev/null +++ b/drivers/pinctrl/ti/Kconfig @@ -0,0 +1,10 @@ +config PINCTRL_TI_IODELAY + tristate "TI IODelay Module pinconf driver" + depends on OF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select REGMAP_MMIO + help + Say Y here to support Texas Instruments' IO delay pinconf driver. + IO delay module is used for the DRA7 SoC family. diff --git a/drivers/pinctrl/ti/Makefile b/drivers/pinctrl/ti/Makefile new file mode 100644 index 000000000000..913744e8b8fa --- /dev/null +++ b/drivers/pinctrl/ti/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PINCTRL_TI_IODELAY) += pinctrl-ti-iodelay.o diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c new file mode 100644 index 000000000000..3b86d3db7358 --- /dev/null +++ b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c @@ -0,0 +1,944 @@ +/* + * Support for configuration of IO Delay module found on Texas Instruments SoCs + * such as DRA7 + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../devicetree.h" + +#define DRIVER_NAME "ti-iodelay" + +/** + * struct ti_iodelay_reg_data - Describes the registers for the iodelay instance + * @signature_mask: CONFIG_REG mask for the signature bits (see TRM) + * @signature_value: CONFIG_REG signature value to be written (see TRM) + * @lock_mask: CONFIG_REG mask for the lock bits (see TRM) + * @lock_val: CONFIG_REG lock value for the lock bits (see TRM) + * @unlock_val:CONFIG_REG unlock value for the lock bits (see TRM) + * @binary_data_coarse_mask: CONFIG_REG coarse mask (see TRM) + * @binary_data_fine_mask: CONFIG_REG fine mask (see TRM) + * @reg_refclk_offset: Refclk register offset + * @refclk_period_mask: Refclk mask + * @reg_coarse_offset: Coarse register configuration offset + * @coarse_delay_count_mask: Coarse delay count mask + * @coarse_ref_count_mask: Coarse ref count mask + * @reg_fine_offset: Fine register configuration offset + * @fine_delay_count_mask: Fine delay count mask + * @fine_ref_count_mask: Fine ref count mask + * @reg_global_lock_offset: Global iodelay module lock register offset + * @global_lock_mask: Lock mask + * @global_unlock_val: Unlock value + * @global_lock_val: Lock value + * @reg_start_offset: Offset to iodelay registers after the CONFIG_REG_0 to 8 + * @reg_nr_per_pin: Number of iodelay registers for each pin + * @regmap_config: Regmap configuration for the IODelay region + */ +struct ti_iodelay_reg_data { + u32 signature_mask; + u32 signature_value; + u32 lock_mask; + u32 lock_val; + u32 unlock_val; + u32 binary_data_coarse_mask; + u32 binary_data_fine_mask; + + u32 reg_refclk_offset; + u32 refclk_period_mask; + + u32 reg_coarse_offset; + u32 coarse_delay_count_mask; + u32 coarse_ref_count_mask; + + u32 reg_fine_offset; + u32 fine_delay_count_mask; + u32 fine_ref_count_mask; + + u32 reg_global_lock_offset; + u32 global_lock_mask; + u32 global_unlock_val; + u32 global_lock_val; + + u32 reg_start_offset; + u32 reg_nr_per_pin; + + struct regmap_config *regmap_config; +}; + +/** + * struct ti_iodelay_reg_values - Computed io_reg configuration values (see TRM) + * @coarse_ref_count: Coarse reference count + * @coarse_delay_count: Coarse delay count + * @fine_ref_count: Fine reference count + * @fine_delay_count: Fine Delay count + * @ref_clk_period: Reference Clock period + * @cdpe: Coarse delay parameter + * @fdpe: Fine delay parameter + */ +struct ti_iodelay_reg_values { + u16 coarse_ref_count; + u16 coarse_delay_count; + + u16 fine_ref_count; + u16 fine_delay_count; + + u16 ref_clk_period; + + u32 cdpe; + u32 fdpe; +}; + +/** + * struct ti_iodelay_cfg - Description of each configuration parameters + * @offset: Configuration register offset + * @a_delay: Agnostic Delay (in ps) + * @g_delay: Gnostic Delay (in ps) + */ +struct ti_iodelay_cfg { + u16 offset; + u16 a_delay; + u16 g_delay; +}; + +/** + * struct ti_iodelay_pingroup - Structure that describes one group + * @cfg: configuration array for the pin (from dt) + * @ncfg: number of configuration values allocated + * @config: pinconf "Config" - currently a dummy value + */ +struct ti_iodelay_pingroup { + struct ti_iodelay_cfg *cfg; + int ncfg; + unsigned long config; +}; + +/** + * struct ti_iodelay_device - Represents information for a iodelay instance + * @dev: Device pointer + * @phys_base: Physical address base of the iodelay device + * @reg_base: Virtual address base of the iodelay device + * @regmap: Regmap for this iodelay instance + * @pctl: Pinctrl device + * @desc: pinctrl descriptor for pctl + * @pa: pinctrl pin wise description + * @reg_data: Register definition data for the IODelay instance + * @reg_init_conf_values: Initial configuration values. + */ +struct ti_iodelay_device { + struct device *dev; + unsigned long phys_base; + void __iomem *reg_base; + struct regmap *regmap; + + struct pinctrl_dev *pctl; + struct pinctrl_desc desc; + struct pinctrl_pin_desc *pa; + + const struct ti_iodelay_reg_data *reg_data; + struct ti_iodelay_reg_values reg_init_conf_values; +}; + +/** + * ti_iodelay_extract() - extract bits for a field + * @val: Register value + * @mask: Mask + * + * Return: extracted value which is appropriately shifted + */ +static inline u32 ti_iodelay_extract(u32 val, u32 mask) +{ + return (val & mask) >> __ffs(mask); +} + +/** + * ti_iodelay_compute_dpe() - Compute equation for delay parameter + * @period: Period to use + * @ref: Reference Count + * @delay: Delay count + * @delay_m: Delay multiplier + * + * Return: Computed delay parameter + */ +static inline u32 ti_iodelay_compute_dpe(u16 period, u16 ref, u16 delay, + u16 delay_m) +{ + u64 m, d; + + /* Handle overflow conditions */ + m = 10 * (u64)period * (u64)ref; + d = 2 * (u64)delay * (u64)delay_m; + + /* Truncate result back to 32 bits */ + return div64_u64(m, d); +} + +/** + * ti_iodelay_pinconf_set() - Configure the pin configuration + * @iod: iodelay device + * @cfg: Configuration + * + * Update the configuration register as per TRM and lockup once done. + * *IMPORTANT NOTE* SoC TRM does recommend doing iodelay programmation only + * while in Isolation. But, then, isolation also implies that every pin + * on the SoC (including DDR) will be isolated out. The only benefit being + * a glitchless configuration, However, the intent of this driver is purely + * to support a "glitchy" configuration where applicable. + * + * Return: 0 in case of success, else appropriate error value + */ +static int ti_iodelay_pinconf_set(struct ti_iodelay_device *iod, + struct ti_iodelay_cfg *cfg) +{ + const struct ti_iodelay_reg_data *reg = iod->reg_data; + struct ti_iodelay_reg_values *ival = &iod->reg_init_conf_values; + struct device *dev = iod->dev; + u32 g_delay_coarse, g_delay_fine; + u32 a_delay_coarse, a_delay_fine; + u32 c_elements, f_elements; + u32 total_delay; + u32 reg_mask, reg_val, tmp_val; + int r; + + /* NOTE: Truncation is expected in all division below */ + g_delay_coarse = cfg->g_delay / 920; + g_delay_fine = ((cfg->g_delay % 920) * 10) / 60; + + a_delay_coarse = cfg->a_delay / ival->cdpe; + a_delay_fine = ((cfg->a_delay % ival->cdpe) * 10) / ival->fdpe; + + c_elements = g_delay_coarse + a_delay_coarse; + f_elements = (g_delay_fine + a_delay_fine) / 10; + + if (f_elements > 22) { + total_delay = c_elements * ival->cdpe + f_elements * ival->fdpe; + c_elements = total_delay / ival->cdpe; + f_elements = (total_delay % ival->cdpe) / ival->fdpe; + } + + reg_mask = reg->signature_mask; + reg_val = reg->signature_value << __ffs(reg->signature_mask); + + reg_mask |= reg->binary_data_coarse_mask; + tmp_val = c_elements << __ffs(reg->binary_data_coarse_mask); + if (tmp_val & ~reg->binary_data_coarse_mask) { + dev_err(dev, "Masking overflow of coarse elements %08x\n", + tmp_val); + tmp_val &= reg->binary_data_coarse_mask; + } + reg_val |= tmp_val; + + reg_mask |= reg->binary_data_fine_mask; + tmp_val = f_elements << __ffs(reg->binary_data_fine_mask); + if (tmp_val & ~reg->binary_data_fine_mask) { + dev_err(dev, "Masking overflow of fine elements %08x\n", + tmp_val); + tmp_val &= reg->binary_data_fine_mask; + } + reg_val |= tmp_val; + + /* + * NOTE: we leave the iodelay values unlocked - this is to work around + * situations such as those found with mmc mode change. + * However, this leaves open any unwarranted changes to padconf register + * impacting iodelay configuration. Use with care! + */ + reg_mask |= reg->lock_mask; + reg_val |= reg->unlock_val << __ffs(reg->lock_mask); + r = regmap_update_bits(iod->regmap, cfg->offset, reg_mask, reg_val); + + dev_info(dev, "Set reg 0x%x Delay(a: %d g: %d), Elements(C=%d F=%d)0x%x\n", + cfg->offset, cfg->a_delay, cfg->g_delay, c_elements, + f_elements, reg_val); + + return r; +} + +/** + * ti_iodelay_pinconf_init_dev() - Initialize IODelay device + * @iod: iodelay device + * + * Unlocks the iodelay region, computes the common parameters + * + * Return: 0 in case of success, else appropriate error value + */ +static int ti_iodelay_pinconf_init_dev(struct ti_iodelay_device *iod) +{ + const struct ti_iodelay_reg_data *reg = iod->reg_data; + struct device *dev = iod->dev; + struct ti_iodelay_reg_values *ival = &iod->reg_init_conf_values; + u32 val; + int r; + + /* unlock the iodelay region */ + r = regmap_update_bits(iod->regmap, reg->reg_global_lock_offset, + reg->global_lock_mask, reg->global_unlock_val); + if (r) + return r; + + /* Read up Recalibration sequence done by bootloader */ + r = regmap_read(iod->regmap, reg->reg_refclk_offset, &val); + if (r) + return r; + ival->ref_clk_period = ti_iodelay_extract(val, reg->refclk_period_mask); + dev_dbg(dev, "refclk_period=0x%04x\n", ival->ref_clk_period); + + r = regmap_read(iod->regmap, reg->reg_coarse_offset, &val); + if (r) + return r; + ival->coarse_ref_count = + ti_iodelay_extract(val, reg->coarse_ref_count_mask); + ival->coarse_delay_count = + ti_iodelay_extract(val, reg->coarse_delay_count_mask); + if (!ival->coarse_delay_count) { + dev_err(dev, "Invalid Coarse delay count (0) (reg=0x%08x)\n", + val); + return -EINVAL; + } + ival->cdpe = ti_iodelay_compute_dpe(ival->ref_clk_period, + ival->coarse_ref_count, + ival->coarse_delay_count, 88); + if (!ival->cdpe) { + dev_err(dev, "Invalid cdpe computed params = %d %d %d\n", + ival->ref_clk_period, ival->coarse_ref_count, + ival->coarse_delay_count); + return -EINVAL; + } + dev_dbg(iod->dev, "coarse: ref=0x%04x delay=0x%04x cdpe=0x%08x\n", + ival->coarse_ref_count, ival->coarse_delay_count, ival->cdpe); + + r = regmap_read(iod->regmap, reg->reg_fine_offset, &val); + if (r) + return r; + ival->fine_ref_count = + ti_iodelay_extract(val, reg->fine_ref_count_mask); + ival->fine_delay_count = + ti_iodelay_extract(val, reg->fine_delay_count_mask); + if (!ival->fine_delay_count) { + dev_err(dev, "Invalid Fine delay count (0) (reg=0x%08x)\n", + val); + return -EINVAL; + } + ival->fdpe = ti_iodelay_compute_dpe(ival->ref_clk_period, + ival->fine_ref_count, + ival->fine_delay_count, 264); + if (!ival->fdpe) { + dev_err(dev, "Invalid fdpe(0) computed params = %d %d %d\n", + ival->ref_clk_period, ival->fine_ref_count, + ival->fine_delay_count); + return -EINVAL; + } + dev_dbg(iod->dev, "fine: ref=0x%04x delay=0x%04x fdpe=0x%08x\n", + ival->fine_ref_count, ival->fine_delay_count, ival->fdpe); + + return 0; +} + +/** + * ti_iodelay_pinconf_deinit_dev() - deinit the iodelay device + * @iod: IODelay device + * + * Deinitialize the IODelay device (basically just lock the region back up. + */ +static void ti_iodelay_pinconf_deinit_dev(struct ti_iodelay_device *iod) +{ + const struct ti_iodelay_reg_data *reg = iod->reg_data; + + /* lock the iodelay region back again */ + regmap_update_bits(iod->regmap, reg->reg_global_lock_offset, + reg->global_lock_mask, reg->global_lock_val); +} + +/** + * ti_iodelay_get_pingroup() - Find the group mapped by a group selector + * @iod: iodelay device + * @selector: Group Selector + * + * Return: Corresponding group representing group selector + */ +static struct ti_iodelay_pingroup * +ti_iodelay_get_pingroup(struct ti_iodelay_device *iod, unsigned int selector) +{ + struct group_desc *g; + + g = pinctrl_generic_get_group(iod->pctl, selector); + if (!g) { + dev_err(iod->dev, "%s could not find pingroup %i\n", __func__, + selector); + + return NULL; + } + + return g->data; +} + +/** + * ti_iodelay_offset_to_pin() - get a pin index based on the register offset + * @iod: iodelay driver instance + * @offset: register offset from the base + */ +static int ti_iodelay_offset_to_pin(struct ti_iodelay_device *iod, + unsigned int offset) +{ + const struct ti_iodelay_reg_data *r = iod->reg_data; + unsigned int index; + + if (offset > r->regmap_config->max_register) { + dev_err(iod->dev, "mux offset out of range: 0x%x (0x%x)\n", + offset, r->regmap_config->max_register); + return -EINVAL; + } + + index = (offset - r->reg_start_offset) / r->regmap_config->reg_stride; + index /= r->reg_nr_per_pin; + + return index; +} + +/** + * ti_iodelay_node_iterator() - Iterate iodelay node + * @pctldev: Pin controller driver + * @np: Device node + * @pinctrl_spec: Parsed arguments from device tree + * @pins: Array of pins in the pin group + * @pin_index: Pin index in the pin array + * @data: Pin controller driver specific data + * + */ +static int ti_iodelay_node_iterator(struct pinctrl_dev *pctldev, + struct device_node *np, + const struct of_phandle_args *pinctrl_spec, + int *pins, int pin_index, void *data) +{ + struct ti_iodelay_device *iod; + struct ti_iodelay_cfg *cfg = data; + const struct ti_iodelay_reg_data *r; + struct pinctrl_pin_desc *pd; + int pin; + + iod = pinctrl_dev_get_drvdata(pctldev); + if (!iod) + return -EINVAL; + + r = iod->reg_data; + + if (pinctrl_spec->args_count < r->reg_nr_per_pin) { + dev_err(iod->dev, "invalid args_count for spec: %i\n", + pinctrl_spec->args_count); + + return -EINVAL; + } + + /* Index plus two value cells */ + cfg[pin_index].offset = pinctrl_spec->args[0]; + cfg[pin_index].a_delay = pinctrl_spec->args[1] & 0xffff; + cfg[pin_index].g_delay = pinctrl_spec->args[2] & 0xffff; + + pin = ti_iodelay_offset_to_pin(iod, cfg[pin_index].offset); + if (pin < 0) { + dev_err(iod->dev, "could not add functions for %s %ux\n", + np->name, cfg[pin_index].offset); + return -ENODEV; + } + pins[pin_index] = pin; + + pd = &iod->pa[pin]; + pd->drv_data = &cfg[pin_index]; + + dev_dbg(iod->dev, "%s offset=%x a_delay = %d g_delay = %d\n", + np->name, cfg[pin_index].offset, cfg[pin_index].a_delay, + cfg[pin_index].g_delay); + + return 0; +} + +/** + * ti_iodelay_dt_node_to_map() - Map a device tree node to appropriate group + * @pctldev: pinctrl device representing IODelay device + * @np: Node Pointer (device tree) + * @map: Pinctrl Map returned back to pinctrl framework + * @num_maps: Number of maps (1) + * + * Maps the device tree description into a group of configuration parameters + * for iodelay block entry. + * + * Return: 0 in case of success, else appropriate error value + */ +static int ti_iodelay_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct ti_iodelay_device *iod; + struct ti_iodelay_cfg *cfg; + struct ti_iodelay_pingroup *g; + const char *name = "pinctrl-pin-array"; + int rows, *pins, error = -EINVAL, i; + + iod = pinctrl_dev_get_drvdata(pctldev); + if (!iod) + return -EINVAL; + + rows = pinctrl_count_index_with_args(np, name); + if (rows == -EINVAL) + return rows; + + *map = devm_kzalloc(iod->dev, sizeof(**map), GFP_KERNEL); + if (!*map) + return -ENOMEM; + *num_maps = 0; + + g = devm_kzalloc(iod->dev, sizeof(*g), GFP_KERNEL); + if (!g) { + error = -ENOMEM; + goto free_map; + } + + pins = devm_kzalloc(iod->dev, sizeof(*pins) * rows, GFP_KERNEL); + if (!pins) + goto free_group; + + cfg = devm_kzalloc(iod->dev, sizeof(*cfg) * rows, GFP_KERNEL); + if (!cfg) { + error = -ENOMEM; + goto free_pins; + } + + for (i = 0; i < rows; i++) { + struct of_phandle_args pinctrl_spec; + + error = pinctrl_parse_index_with_args(np, name, i, + &pinctrl_spec); + if (error) + goto free_data; + + error = ti_iodelay_node_iterator(pctldev, np, &pinctrl_spec, + pins, i, cfg); + if (error) + goto free_data; + } + + g->cfg = cfg; + g->ncfg = i; + g->config = PIN_CONFIG_END; + + error = pinctrl_generic_add_group(iod->pctl, np->name, pins, i, g); + if (error < 0) + goto free_data; + + (*map)->type = PIN_MAP_TYPE_CONFIGS_GROUP; + (*map)->data.configs.group_or_pin = np->name; + (*map)->data.configs.configs = &g->config; + (*map)->data.configs.num_configs = 1; + *num_maps = 1; + + return 0; + +free_data: + devm_kfree(iod->dev, cfg); +free_pins: + devm_kfree(iod->dev, pins); +free_group: + devm_kfree(iod->dev, g); +free_map: + devm_kfree(iod->dev, *map); + + return error; +} + +/** + * ti_iodelay_pinconf_group_get() - Get the group configuration + * @pctldev: pinctrl device representing IODelay device + * @selector: Group selector + * @config: Configuration returned + * + * Return: The configuration if the group is valid, else returns -EINVAL + */ +static int ti_iodelay_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *config) +{ + struct ti_iodelay_device *iod; + struct device *dev; + struct ti_iodelay_pingroup *group; + + iod = pinctrl_dev_get_drvdata(pctldev); + dev = iod->dev; + group = ti_iodelay_get_pingroup(iod, selector); + + if (!group) + return -EINVAL; + + *config = group->config; + return 0; +} + +/** + * ti_iodelay_pinconf_group_set() - Configure the groups of pins + * @pctldev: pinctrl device representing IODelay device + * @selector: Group selector + * @configs: Configurations + * @num_configs: Number of configurations + * + * Return: 0 if all went fine, else appropriate error value. + */ +static int ti_iodelay_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + struct ti_iodelay_device *iod; + struct device *dev; + struct ti_iodelay_pingroup *group; + int i; + + iod = pinctrl_dev_get_drvdata(pctldev); + dev = iod->dev; + group = ti_iodelay_get_pingroup(iod, selector); + + if (num_configs != 1) { + dev_err(dev, "Unsupported number of configurations %d\n", + num_configs); + return -EINVAL; + } + + if (*configs != PIN_CONFIG_END) { + dev_err(dev, "Unsupported configuration\n"); + return -EINVAL; + } + + for (i = 0; i < group->ncfg; i++) { + if (ti_iodelay_pinconf_set(iod, &group->cfg[i])) + return -ENOTSUPP; + } + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +/** + * ti_iodelay_pin_to_offset() - get pin register offset based on the pin index + * @iod: iodelay driver instance + * @selector: Pin index + */ +static unsigned int ti_iodelay_pin_to_offset(struct ti_iodelay_device *iod, + unsigned int selector) +{ + const struct ti_iodelay_reg_data *r = iod->reg_data; + unsigned int offset; + + offset = selector * r->regmap_config->reg_stride; + offset *= r->reg_nr_per_pin; + offset += r->reg_start_offset; + + return offset; +} + +static void ti_iodelay_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned int pin) +{ + struct ti_iodelay_device *iod; + struct pinctrl_pin_desc *pd; + struct ti_iodelay_cfg *cfg; + const struct ti_iodelay_reg_data *r; + unsigned long offset; + u32 in, oen, out; + + iod = pinctrl_dev_get_drvdata(pctldev); + r = iod->reg_data; + + offset = ti_iodelay_pin_to_offset(iod, pin); + if (pin < 0) { + dev_err(iod->dev, "invalid pin offset for pin%i\n", pin); + + return; + } + + pd = &iod->pa[pin]; + cfg = pd->drv_data; + + regmap_read(iod->regmap, offset, &in); + regmap_read(iod->regmap, offset + r->regmap_config->reg_stride, &oen); + regmap_read(iod->regmap, offset + r->regmap_config->reg_stride * 2, + &out); + + seq_printf(s, "%lx a: %i g: %i (%08x %08x %08x) %s ", + iod->phys_base + offset, + cfg ? cfg->a_delay : -1, + cfg ? cfg->g_delay : -1, + in, oen, out, DRIVER_NAME); +} + +/** + * ti_iodelay_pinconf_group_dbg_show() - show the group information + * @pctldev: Show the group information + * @s: Sequence file + * @selector: Group selector + * + * Provide the configuration information of the selected group + */ +static void ti_iodelay_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned int selector) +{ + struct ti_iodelay_device *iod; + struct device *dev; + struct ti_iodelay_pingroup *group; + int i; + + iod = pinctrl_dev_get_drvdata(pctldev); + dev = iod->dev; + group = ti_iodelay_get_pingroup(iod, selector); + if (!group) + return; + + for (i = 0; i < group->ncfg; i++) { + struct ti_iodelay_cfg *cfg; + u32 reg = 0; + + cfg = &group->cfg[i]; + regmap_read(iod->regmap, cfg->offset, ®), + seq_printf(s, "\n\t0x%08x = 0x%08x (%3d, %3d)", + cfg->offset, reg, cfg->a_delay, + cfg->g_delay); + } +} +#endif + +static struct pinctrl_ops ti_iodelay_pinctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, +#ifdef CONFIG_DEBUG_FS + .pin_dbg_show = ti_iodelay_pin_dbg_show, +#endif + .dt_node_to_map = ti_iodelay_dt_node_to_map, +}; + +static struct pinconf_ops ti_iodelay_pinctrl_pinconf_ops = { + .pin_config_group_get = ti_iodelay_pinconf_group_get, + .pin_config_group_set = ti_iodelay_pinconf_group_set, +#ifdef CONFIG_DEBUG_FS + .pin_config_group_dbg_show = ti_iodelay_pinconf_group_dbg_show, +#endif +}; + +/** + * ti_iodelay_alloc_pins() - Allocate structures needed for pins for iodelay + * @dev: Device pointer + * @iod: iodelay device + * @base_phy: Base Physical Address + * + * Return: 0 if all went fine, else appropriate error value. + */ +static int ti_iodelay_alloc_pins(struct device *dev, + struct ti_iodelay_device *iod, u32 base_phy) +{ + const struct ti_iodelay_reg_data *r = iod->reg_data; + struct pinctrl_pin_desc *pin; + u32 phy_reg; + int nr_pins, i; + + nr_pins = ti_iodelay_offset_to_pin(iod, r->regmap_config->max_register); + dev_dbg(dev, "Allocating %i pins\n", nr_pins); + + iod->pa = devm_kzalloc(dev, sizeof(*iod->pa) * nr_pins, GFP_KERNEL); + if (!iod->pa) + return -ENOMEM; + + iod->desc.pins = iod->pa; + iod->desc.npins = nr_pins; + + phy_reg = r->reg_start_offset + base_phy; + + for (i = 0; i < nr_pins; i++, phy_reg += 4) { + pin = &iod->pa[i]; + pin->number = i; + } + + return 0; +} + +static struct regmap_config dra7_iodelay_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xd1c, +}; + +static struct ti_iodelay_reg_data dra7_iodelay_data = { + .signature_mask = 0x0003f000, + .signature_value = 0x29, + .lock_mask = 0x00000400, + .lock_val = 1, + .unlock_val = 0, + .binary_data_coarse_mask = 0x000003e0, + .binary_data_fine_mask = 0x0000001f, + + .reg_refclk_offset = 0x14, + .refclk_period_mask = 0xffff, + + .reg_coarse_offset = 0x18, + .coarse_delay_count_mask = 0xffff0000, + .coarse_ref_count_mask = 0x0000ffff, + + .reg_fine_offset = 0x1C, + .fine_delay_count_mask = 0xffff0000, + .fine_ref_count_mask = 0x0000ffff, + + .reg_global_lock_offset = 0x2c, + .global_lock_mask = 0x0000ffff, + .global_unlock_val = 0x0000aaaa, + .global_lock_val = 0x0000aaab, + + .reg_start_offset = 0x30, + .reg_nr_per_pin = 3, + .regmap_config = &dra7_iodelay_regmap_config, +}; + +static const struct of_device_id ti_iodelay_of_match[] = { + {.compatible = "ti,dra7-iodelay", .data = &dra7_iodelay_data}, + { /* Hopefully no more.. */ }, +}; +MODULE_DEVICE_TABLE(of, ti_iodelay_of_match); + +/** + * ti_iodelay_probe() - Standard probe + * @pdev: platform device + * + * Return: 0 if all went fine, else appropriate error value. + */ +static int ti_iodelay_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = of_node_get(dev->of_node); + const struct of_device_id *match; + struct resource *res; + struct ti_iodelay_device *iod; + int ret = 0; + + if (!np) { + ret = -EINVAL; + dev_err(dev, "No OF node\n"); + goto exit_out; + } + + match = of_match_device(ti_iodelay_of_match, dev); + if (!match) { + ret = -EINVAL; + dev_err(dev, "No DATA match\n"); + goto exit_out; + } + + iod = devm_kzalloc(dev, sizeof(*iod), GFP_KERNEL); + if (!iod) { + ret = -ENOMEM; + goto exit_out; + } + iod->dev = dev; + iod->reg_data = match->data; + + /* So far We can assume there is only 1 bank of registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Missing MEM resource\n"); + ret = -ENODEV; + goto exit_out; + } + + iod->phys_base = res->start; + iod->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(iod->reg_base)) { + ret = PTR_ERR(iod->reg_base); + goto exit_out; + } + + iod->regmap = devm_regmap_init_mmio(dev, iod->reg_base, + iod->reg_data->regmap_config); + if (IS_ERR(iod->regmap)) { + dev_err(dev, "Regmap MMIO init failed.\n"); + ret = PTR_ERR(iod->regmap); + goto exit_out; + } + + if (ti_iodelay_pinconf_init_dev(iod)) + goto exit_out; + + ret = ti_iodelay_alloc_pins(dev, iod, res->start); + if (ret) + goto exit_out; + + iod->desc.pctlops = &ti_iodelay_pinctrl_ops; + /* no pinmux ops - we are pinconf */ + iod->desc.confops = &ti_iodelay_pinctrl_pinconf_ops; + iod->desc.name = dev_name(dev); + iod->desc.owner = THIS_MODULE; + + iod->pctl = pinctrl_register(&iod->desc, dev, iod); + if (!iod->pctl) { + dev_err(dev, "Failed to register pinctrl\n"); + ret = -ENODEV; + goto exit_out; + } + + platform_set_drvdata(pdev, iod); + +exit_out: + of_node_put(np); + return ret; +} + +/** + * ti_iodelay_remove() - standard remove + * @pdev: platform device + * + * Return: 0 if all went fine, else appropriate error value. + */ +static int ti_iodelay_remove(struct platform_device *pdev) +{ + struct ti_iodelay_device *iod = platform_get_drvdata(pdev); + + if (!iod) + return 0; + + if (iod->pctl) + pinctrl_unregister(iod->pctl); + + ti_iodelay_pinconf_deinit_dev(iod); + + /* Expect other allocations to be freed by devm */ + + return 0; +} + +static struct platform_driver ti_iodelay_driver = { + .probe = ti_iodelay_probe, + .remove = ti_iodelay_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .of_match_table = ti_iodelay_of_match, + }, +}; +module_platform_driver(ti_iodelay_driver); + +MODULE_AUTHOR("Texas Instruments, Inc."); +MODULE_DESCRIPTION("Pinconf driver for TI's IO Delay module"); +MODULE_LICENSE("GPL v2"); From 102ecc471b9d2f41f10c586f077a0d8e853335f8 Mon Sep 17 00:00:00 2001 From: Gao Pan Date: Wed, 4 Jan 2017 17:38:16 +0800 Subject: [PATCH 0288/1587] spi: fsl-lpspi: fix indentation error This patch fixes the indentation error in spi-fsl-lpspi.c. Signed-off-by: Gao Pan Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 2b93bc605b91..cb3c73007ca1 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -512,9 +512,9 @@ static int fsl_lpspi_remove(struct platform_device *pdev) static struct platform_driver fsl_lpspi_driver = { .driver = { - .name = DRIVER_NAME, - .of_match_table = fsl_lpspi_dt_ids, - }, + .name = DRIVER_NAME, + .of_match_table = fsl_lpspi_dt_ids, + }, .probe = fsl_lpspi_probe, .remove = fsl_lpspi_remove, }; From e2e8f619adaaa1b31c3739640beb0bd72ac87f4d Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Mon, 26 Dec 2016 14:23:09 +0100 Subject: [PATCH 0289/1587] scsi: qla2xxx: silence -Wformat-security warning qla24xx_enable_msix() calls scnprintf() with a non-literal format string. This makes clang report -Wformat-security warnings when compiling this function: drivers/scsi/qla2xxx/qla_isr.c:3083:7: error: format string is not a string literal (potentially insecure) [-Werror,-Wformat-security] msix_entries[i].name); ^~~~~~~~~~~~~~~~~~~~ drivers/scsi/qla2xxx/qla_isr.c:3083:7: note: treat the string as an argument to avoid this msix_entries[i].name); ^ "%s", drivers/scsi/qla2xxx/qla_isr.c:3119:7: error: format string is not a string literal (potentially insecure) [-Werror,-Wformat-security] msix_entries[QLA_ATIO_VECTOR].name); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/qla2xxx/qla_isr.c:3119:7: note: treat the string as an argument to avoid this msix_entries[QLA_ATIO_VECTOR].name); ^ "%s", Even though msix_entries[...].name are initialized as literal strings with no % character and are never modified, introduce a "%s" format parameter in order to silence this -Wformat-security warning and make clang able to detect at compile time real bugs related to string formatting. [mkp: typo] Signed-off-by: Nicolas Iooss Reviewed-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_isr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 5093ca9b02ec..474b415217df 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3080,7 +3080,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) qentry->handle = rsp; rsp->msix = qentry; scnprintf(qentry->name, sizeof(qentry->name), - msix_entries[i].name); + "%s", msix_entries[i].name); if (IS_P3P_TYPE(ha)) ret = request_irq(qentry->vector, qla82xx_msix_entries[i].handler, @@ -3116,7 +3116,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) rsp->msix = qentry; qentry->handle = rsp; scnprintf(qentry->name, sizeof(qentry->name), - msix_entries[QLA_ATIO_VECTOR].name); + "%s", msix_entries[QLA_ATIO_VECTOR].name); qentry->in_use = 1; ret = request_irq(qentry->vector, msix_entries[QLA_ATIO_VECTOR].handler, From 44a8f954449c604b7b0a73a0316a8c4ed3487784 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Mon, 26 Dec 2016 14:23:10 +0100 Subject: [PATCH 0290/1587] scsi: qla2xxx: make msix_entries const msix_entries and qla82xx_msix_entries arrays are never modified in drivers/scsi/qla2xxx/qla_isr.c. Move their contents to read-only data. Signed-off-by: Nicolas Iooss Reviewed-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_isr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 474b415217df..b9c113e47346 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3003,14 +3003,14 @@ struct qla_init_msix_entry { irq_handler_t handler; }; -static struct qla_init_msix_entry msix_entries[] = { +static const struct qla_init_msix_entry msix_entries[] = { { "qla2xxx (default)", qla24xx_msix_default }, { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, { "qla2xxx (atio_q)", qla83xx_msix_atio_q }, { "qla2xxx (qpair_multiq)", qla2xxx_msix_rsp_q }, }; -static struct qla_init_msix_entry qla82xx_msix_entries[] = { +static const struct qla_init_msix_entry qla82xx_msix_entries[] = { { "qla2xxx (default)", qla82xx_msix_default }, { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q }, }; @@ -3284,7 +3284,7 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair, struct qla_msix_entry *msix, int vector_type) { - struct qla_init_msix_entry *intr = &msix_entries[vector_type]; + const struct qla_init_msix_entry *intr = &msix_entries[vector_type]; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); int ret; From 577419f70463378c224d4b92e31b22c2877c4389 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Dec 2016 22:20:38 +0000 Subject: [PATCH 0291/1587] scsi: qla2xxx: rename {vendor|hba}_indentifer to {vendor|hba}_identifer Rename the vendor_indentifer and hba_indentifer fields to correct spelling. Signed-off-by: Colin Ian King Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 4 ++-- drivers/scsi/qla2xxx/qla_gs.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index f7df01b76714..ef699b66b685 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2247,7 +2247,7 @@ struct ct_fdmiv2_hba_attr { uint32_t num_ports; uint8_t fabric_name[WWN_SIZE]; uint8_t bios_name[32]; - uint8_t vendor_indentifer[8]; + uint8_t vendor_identifier[8]; } a; }; @@ -2422,7 +2422,7 @@ struct ct_sns_req { } rsnn_nn; struct { - uint8_t hba_indentifier[8]; + uint8_t hba_identifier[8]; } ghat; struct { diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 94e8a8592f69..ee3df8794806 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1939,15 +1939,15 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) /* Vendor Identifier */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_TYPE_VENDOR_IDENTIFIER); - snprintf(eiter->a.vendor_indentifer, sizeof(eiter->a.vendor_indentifer), + snprintf(eiter->a.vendor_identifier, sizeof(eiter->a.vendor_identifier), "%s", "QLGC"); - alen = strlen(eiter->a.vendor_indentifer); + alen = strlen(eiter->a.vendor_identifier); alen += 4 - (alen & 3); eiter->len = cpu_to_be16(4 + alen); size += 4 + alen; ql_dbg(ql_dbg_disc, vha, 0x20b1, - "Vendor Identifier = %s.\n", eiter->a.vendor_indentifer); + "Vendor Identifier = %s.\n", eiter->a.vendor_identifier); /* Update MS request size. */ qla2x00_update_ms_fdmi_iocb(vha, size + 16); From 984dc46c5715fec4329861f93f30c76b8d680e8d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jan 2017 10:41:15 +0100 Subject: [PATCH 0292/1587] scsi: bfa: remove bfa_fcs_mod_s Just call the functions directly instead of obsfucating the call chain. This was in reply to a patch from Kees Cook to constify the function pointer struct bfa_fcs_mod_s, but it turns out there is no reason to have this indirection at all. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_fcs.c | 183 ++++++++++--------------------------- drivers/scsi/bfa/bfa_fcs.h | 4 - 2 files changed, 47 insertions(+), 140 deletions(-) diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index 1e7e139d71ea..4aa61e20e82d 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -27,24 +27,6 @@ BFA_TRC_FILE(FCS, FCS); -/* - * FCS sub-modules - */ -struct bfa_fcs_mod_s { - void (*attach) (struct bfa_fcs_s *fcs); - void (*modinit) (struct bfa_fcs_s *fcs); - void (*modexit) (struct bfa_fcs_s *fcs); -}; - -#define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit } - -static struct bfa_fcs_mod_s fcs_modules[] = { - { bfa_fcs_port_attach, NULL, NULL }, - { bfa_fcs_uf_attach, NULL, NULL }, - { bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit, - bfa_fcs_fabric_modexit }, -}; - /* * fcs_api BFA FCS API */ @@ -58,53 +40,20 @@ bfa_fcs_exit_comp(void *fcs_cbarg) complete(&bfad->comp); } - - -/* - * fcs_api BFA FCS API - */ - -/* - * fcs attach -- called once to initialize data structures at driver attach time - */ -void -bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, - bfa_boolean_t min_cfg) -{ - int i; - struct bfa_fcs_mod_s *mod; - - fcs->bfa = bfa; - fcs->bfad = bfad; - fcs->min_cfg = min_cfg; - fcs->num_rport_logins = 0; - - bfa->fcs = BFA_TRUE; - fcbuild_init(); - - for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) { - mod = &fcs_modules[i]; - if (mod->attach) - mod->attach(fcs); - } -} - /* * fcs initialization, called once after bfa initialization is complete */ void bfa_fcs_init(struct bfa_fcs_s *fcs) { - int i; - struct bfa_fcs_mod_s *mod; - - for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) { - mod = &fcs_modules[i]; - if (mod->modinit) - mod->modinit(fcs); - } + bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE); + bfa_trc(fcs, 0); } +/* + * fcs_api BFA FCS API + */ + /* * FCS update cfg - reset the pwwn/nwwn of fabric base logical port * with values learned during bfa_init firmware GETATTR REQ. @@ -180,26 +129,14 @@ bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, void bfa_fcs_exit(struct bfa_fcs_s *fcs) { - struct bfa_fcs_mod_s *mod; - int nmods, i; - bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs); - - nmods = ARRAY_SIZE(fcs_modules); - - for (i = 0; i < nmods; i++) { - - mod = &fcs_modules[i]; - if (mod->modexit) { - bfa_wc_up(&fcs->wc); - mod->modexit(fcs); - } - } - + bfa_wc_up(&fcs->wc); + bfa_trc(fcs, 0); + bfa_lps_delete(fcs->fabric.lps); + bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_DELETE); bfa_wc_wait(&fcs->wc); } - /* * Fabric module implementation. */ @@ -1127,62 +1064,6 @@ bfa_fcs_fabric_stop_comp(void *cbarg) * fcs_fabric_public fabric public functions */ -/* - * Attach time initialization. - */ -void -bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - fabric = &fcs->fabric; - memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s)); - - /* - * Initialize base fabric. - */ - fabric->fcs = fcs; - INIT_LIST_HEAD(&fabric->vport_q); - INIT_LIST_HEAD(&fabric->vf_q); - fabric->lps = bfa_lps_alloc(fcs->bfa); - WARN_ON(!fabric->lps); - - /* - * Initialize fabric delete completion handler. Fabric deletion is - * complete when the last vport delete is complete. - */ - bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric); - bfa_wc_up(&fabric->wc); /* For the base port */ - - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); - bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL); -} - -void -bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs) -{ - bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE); - bfa_trc(fcs, 0); -} - -/* - * Module cleanup - */ -void -bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - bfa_trc(fcs, 0); - - /* - * Cleanup base fabric. - */ - fabric = &fcs->fabric; - bfa_lps_delete(fabric->lps); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE); -} - /* * Fabric module stop -- stop FCS actions */ @@ -1633,12 +1514,6 @@ bfa_fcs_port_event_handler(void *cbarg, enum bfa_port_linkstate event) } } -void -bfa_fcs_port_attach(struct bfa_fcs_s *fcs) -{ - bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs); -} - /* * BFA FCS UF ( Unsolicited Frames) */ @@ -1706,8 +1581,44 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf) bfa_uf_free(uf); } +/* + * fcs attach -- called once to initialize data structures at driver attach time + */ void -bfa_fcs_uf_attach(struct bfa_fcs_s *fcs) +bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, + bfa_boolean_t min_cfg) { + struct bfa_fcs_fabric_s *fabric = &fcs->fabric; + + fcs->bfa = bfa; + fcs->bfad = bfad; + fcs->min_cfg = min_cfg; + fcs->num_rport_logins = 0; + + bfa->fcs = BFA_TRUE; + fcbuild_init(); + + bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs); bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs); + + memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s)); + + /* + * Initialize base fabric. + */ + fabric->fcs = fcs; + INIT_LIST_HEAD(&fabric->vport_q); + INIT_LIST_HEAD(&fabric->vf_q); + fabric->lps = bfa_lps_alloc(fcs->bfa); + WARN_ON(!fabric->lps); + + /* + * Initialize fabric delete completion handler. Fabric deletion is + * complete when the last vport delete is complete. + */ + bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric); + bfa_wc_up(&fabric->wc); /* For the base port */ + + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); + bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL); } diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index 0f797a55d504..e60f72b766ea 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -808,9 +808,7 @@ void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports); /* * fabric protected interface functions */ -void bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs); void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs); void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric); void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric); void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, @@ -827,8 +825,6 @@ void bfa_fcs_fabric_nsymb_init(struct bfa_fcs_fabric_s *fabric); void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, wwn_t fabric_name); u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs); -void bfa_fcs_port_attach(struct bfa_fcs_s *fcs); void bfa_fcs_fabric_modstop(struct bfa_fcs_s *fcs); void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, enum bfa_fcs_fabric_event event); From eab5c1503b604216e352151618cd78d5806dee1a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 18 Nov 2016 07:28:16 +0100 Subject: [PATCH 0293/1587] scsi: pmcraid: switch to pci_alloc_irq_vectors Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/pmcraid.c | 84 +++++++++++++++++++----------------------- drivers/scsi/pmcraid.h | 1 - 2 files changed, 37 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 337982cf3d63..49e70a383afa 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -4587,16 +4587,14 @@ static void pmcraid_tasklet_function(unsigned long instance) static void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) { + struct pci_dev *pdev = pinstance->pdev; int i; for (i = 0; i < pinstance->num_hrrq; i++) - free_irq(pinstance->hrrq_vector[i].vector, - &(pinstance->hrrq_vector[i])); + free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]); - if (pinstance->interrupt_mode) { - pci_disable_msix(pinstance->pdev); - pinstance->interrupt_mode = 0; - } + pinstance->interrupt_mode = 0; + pci_free_irq_vectors(pdev); } /** @@ -4609,60 +4607,52 @@ void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) static int pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) { - int rc; struct pci_dev *pdev = pinstance->pdev; + unsigned int irq_flag = PCI_IRQ_LEGACY, flag; + int num_hrrq, rc, i; + irq_handler_t isr; - if ((pmcraid_enable_msix) && - (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) { - int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; - struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; - int i; - for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++) - entries[i].entry = i; + if (pmcraid_enable_msix) + irq_flag |= PCI_IRQ_MSIX; - num_hrrq = pci_enable_msix_range(pdev, entries, 1, num_hrrq); - if (num_hrrq < 0) - goto pmcraid_isr_legacy; + num_hrrq = pci_alloc_irq_vectors(pdev, 1, PMCRAID_NUM_MSIX_VECTORS, + irq_flag); + if (num_hrrq < 0) + return num_hrrq; - for (i = 0; i < num_hrrq; i++) { - pinstance->hrrq_vector[i].hrrq_id = i; - pinstance->hrrq_vector[i].drv_inst = pinstance; - pinstance->hrrq_vector[i].vector = entries[i].vector; - rc = request_irq(pinstance->hrrq_vector[i].vector, - pmcraid_isr_msix, 0, - PMCRAID_DRIVER_NAME, - &(pinstance->hrrq_vector[i])); + if (pdev->msix_enabled) { + flag = 0; + isr = pmcraid_isr_msix; + } else { + flag = IRQF_SHARED; + isr = pmcraid_isr; + } - if (rc) { - int j; - for (j = 0; j < i; j++) - free_irq(entries[j].vector, - &(pinstance->hrrq_vector[j])); - pci_disable_msix(pdev); - goto pmcraid_isr_legacy; - } - } + for (i = 0; i < num_hrrq; i++) { + struct pmcraid_isr_param *vec = &pinstance->hrrq_vector[i]; - pinstance->num_hrrq = num_hrrq; + vec->hrrq_id = i; + vec->drv_inst = pinstance; + rc = request_irq(pci_irq_vector(pdev, i), isr, flag, + PMCRAID_DRIVER_NAME, vec); + if (rc) + goto out_unwind; + } + + pinstance->num_hrrq = num_hrrq; + if (pdev->msix_enabled) { pinstance->interrupt_mode = 1; iowrite32(DOORBELL_INTR_MODE_MSIX, pinstance->int_regs.host_ioa_interrupt_reg); ioread32(pinstance->int_regs.host_ioa_interrupt_reg); - goto pmcraid_isr_out; } -pmcraid_isr_legacy: - /* If MSI-X registration failed fallback to legacy mode, where - * only one hrrq entry will be used - */ - pinstance->hrrq_vector[0].hrrq_id = 0; - pinstance->hrrq_vector[0].drv_inst = pinstance; - pinstance->hrrq_vector[0].vector = pdev->irq; - pinstance->num_hrrq = 1; + return 0; - rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED, - PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]); -pmcraid_isr_out: +out_unwind: + while (--i > 0) + free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]); + pci_free_irq_vectors(pdev); return rc; } diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index e1d150f3fd4d..568b18a2f47d 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -628,7 +628,6 @@ struct pmcraid_interrupts { /* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */ struct pmcraid_isr_param { struct pmcraid_instance *drv_inst; - u16 vector; /* allocated msi-x vector */ u8 hrrq_id; /* hrrq entry index */ }; From b6f0ec3621d73bc2976a4f2ee2bf9d02ecfd16b6 Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Tue, 3 Jan 2017 16:01:40 -0800 Subject: [PATCH 0294/1587] scsi: esas2r: Fix format string type mistakes This adds the missing __printf attribute which allows compile time format string checking (and will be used by the coming initify gcc plugin). Additionally, this fixes the warnings exposed by the attribute. Signed-off-by: Emese Revfy [kees: split scsi/acpi, merged attr and fix, new commit messages] Signed-off-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/esas2r/esas2r_init.c | 2 +- drivers/scsi/esas2r/esas2r_ioctl.c | 2 +- drivers/scsi/esas2r/esas2r_log.h | 4 ++-- drivers/scsi/esas2r/esas2r_main.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index d6e53aee2295..6432a50b26d8 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -237,7 +237,7 @@ static void esas2r_claim_interrupts(struct esas2r_adapter *a) flags |= IRQF_SHARED; esas2r_log(ESAS2R_LOG_INFO, - "esas2r_claim_interrupts irq=%d (%p, %s, %x)", + "esas2r_claim_interrupts irq=%d (%p, %s, %lx)", a->pcid->irq, a, a->name, flags); if (request_irq(a->pcid->irq, diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c index 3e8483410f61..b35ed3829421 100644 --- a/drivers/scsi/esas2r/esas2r_ioctl.c +++ b/drivers/scsi/esas2r/esas2r_ioctl.c @@ -1301,7 +1301,7 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg) ioctl = kzalloc(sizeof(struct atto_express_ioctl), GFP_KERNEL); if (ioctl == NULL) { esas2r_log(ESAS2R_LOG_WARN, - "ioctl_handler kzalloc failed for %d bytes", + "ioctl_handler kzalloc failed for %zu bytes", sizeof(struct atto_express_ioctl)); return -ENOMEM; } diff --git a/drivers/scsi/esas2r/esas2r_log.h b/drivers/scsi/esas2r/esas2r_log.h index 7b6397bb5b94..75b9d23cd736 100644 --- a/drivers/scsi/esas2r/esas2r_log.h +++ b/drivers/scsi/esas2r/esas2r_log.h @@ -61,8 +61,8 @@ enum { #endif }; -int esas2r_log(const long level, const char *format, ...); -int esas2r_log_dev(const long level, +__printf(2, 3) int esas2r_log(const long level, const char *format, ...); +__printf(3, 4) int esas2r_log_dev(const long level, const struct device *dev, const char *format, ...); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 5092c821d088..f2e9d8aa979c 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -198,7 +198,7 @@ static ssize_t write_hw(struct file *file, struct kobject *kobj, GFP_KERNEL); if (a->local_atto_ioctl == NULL) { esas2r_log(ESAS2R_LOG_WARN, - "write_hw kzalloc failed for %d bytes", + "write_hw kzalloc failed for %zu bytes", sizeof(struct atto_ioctl)); return -ENOMEM; } @@ -1186,7 +1186,7 @@ retry: } else { esas2r_log(ESAS2R_LOG_CRIT, "unable to allocate a request for a " - "device reset (%d:%d)!", + "device reset (%d:%llu)!", cmd->device->id, cmd->device->lun); } From ebb7fe2100e8d181c7c3911801444965384ba147 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jan 2017 17:26:21 +0200 Subject: [PATCH 0295/1587] dmaengine: dw: pci: remove LPE Audio DMA ID LPE Audio driver should take care of DMA IPs by itself. Keeping an ID like this in dw_dma_pci.c is anyway wrong since that block has two DMA controllers under one ID (like MFD device). That's also why I didn't include LPE Audio ID for Intel Merrifield previously. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw/pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 0ae6c3b1d34e..7558a9c38fda 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -95,9 +95,8 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = { }; static const struct pci_device_id dw_pci_id_table[] = { - /* Medfield */ + /* Medfield (GPDMA) */ { PCI_VDEVICE(INTEL, 0x0827) }, - { PCI_VDEVICE(INTEL, 0x0830) }, /* BayTrail */ { PCI_VDEVICE(INTEL, 0x0f06) }, From 5df4eb453cbdad34ea55c0ce984a376b33442aa1 Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Thu, 5 Jan 2017 09:09:40 +0100 Subject: [PATCH 0296/1587] dmaengine: stm32-dma: Add error messages if xlate fails This patch adds some error messages when a slave device fails to request a channel. Signed-off-by: M'boumba Cedric Madianga Reviewed-by: Ludovic BARRE Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index fc9738e0f3a3..4eacd9dd5710 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -987,30 +987,36 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { struct stm32_dma_device *dmadev = ofdma->of_dma_data; + struct device *dev = dmadev->ddev.dev; struct stm32_dma_cfg cfg; struct stm32_dma_chan *chan; struct dma_chan *c; - if (dma_spec->args_count < 3) + if (dma_spec->args_count < 4) { + dev_err(dev, "Bad number of cells\n"); return NULL; + } cfg.channel_id = dma_spec->args[0]; cfg.request_line = dma_spec->args[1]; cfg.stream_config = dma_spec->args[2]; - cfg.threshold = 0; + cfg.threshold = dma_spec->args[3]; - if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || (cfg.request_line >= - STM32_DMA_MAX_REQUEST_ID)) + if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || + (cfg.request_line >= STM32_DMA_MAX_REQUEST_ID)) { + dev_err(dev, "Bad channel and/or request id\n"); return NULL; - - if (dma_spec->args_count > 3) - cfg.threshold = dma_spec->args[3]; + } chan = &dmadev->chan[cfg.channel_id]; c = dma_get_slave_channel(&chan->vchan.chan); - if (c) - stm32_dma_set_config(chan, &cfg); + if (!c) { + dev_err(dev, "No more channel avalaible\n"); + return NULL; + } + + stm32_dma_set_config(chan, &cfg); return c; } From b8aa8453918ebfd93d78de56c2afd4b735e02e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Thu, 22 Dec 2016 00:32:25 +0100 Subject: [PATCH 0297/1587] security: Fix inode_getattr documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace arguments @mnt and @dentry with @path. Signed-off-by: Mickaël Salaün Acked-by: Serge Hallyn Signed-off-by: James Morris --- include/linux/lsm_hooks.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 558adfa5c8a8..9cf50ad2fe20 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -352,8 +352,7 @@ * Return 0 if permission is granted. * @inode_getattr: * Check permission before obtaining file attributes. - * @mnt is the vfsmount where the dentry was looked up - * @dentry contains the dentry structure for the file. + * @path contains the path structure for the file. * Return 0 if permission is granted. * @inode_setxattr: * Check permission before setting the extended attributes From 75f271380d49798cc313174e9976aabc5197c93e Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:49 +0100 Subject: [PATCH 0298/1587] udf: use __packed instead of __attribute__ ((packed)) defined in linux/compiler-gcc.h Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/ecma_167.h | 98 +++++++++++++++++++++++------------------------ fs/udf/osta_udf.h | 34 ++++++++-------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h index 4792b771aa80..9f24bd1a9f44 100644 --- a/fs/udf/ecma_167.h +++ b/fs/udf/ecma_167.h @@ -41,7 +41,7 @@ struct charspec { uint8_t charSetType; uint8_t charSetInfo[63]; -} __attribute__ ((packed)); +} __packed; /* Character Set Type (ECMA 167r3 1/7.2.1.1) */ #define CHARSPEC_TYPE_CS0 0x00 /* (1/7.2.2) */ @@ -68,7 +68,7 @@ struct timestamp { uint8_t centiseconds; uint8_t hundredsOfMicroseconds; uint8_t microseconds; -} __attribute__ ((packed)); +} __packed; /* Type and Time Zone (ECMA 167r3 1/7.3.1) */ #define TIMESTAMP_TYPE_MASK 0xF000 @@ -82,7 +82,7 @@ struct regid { uint8_t flags; uint8_t ident[23]; uint8_t identSuffix[8]; -} __attribute__ ((packed)); +} __packed; /* Flags (ECMA 167r3 1/7.4.1) */ #define ENTITYID_FLAGS_DIRTY 0x00 @@ -95,7 +95,7 @@ struct volStructDesc { uint8_t stdIdent[VSD_STD_ID_LEN]; uint8_t structVersion; uint8_t structData[2041]; -} __attribute__ ((packed)); +} __packed; /* Standard Identifier (EMCA 167r2 2/9.1.2) */ #define VSD_STD_ID_NSR02 "NSR02" /* (3/9.1) */ @@ -114,7 +114,7 @@ struct beginningExtendedAreaDesc { uint8_t stdIdent[VSD_STD_ID_LEN]; uint8_t structVersion; uint8_t structData[2041]; -} __attribute__ ((packed)); +} __packed; /* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */ struct terminatingExtendedAreaDesc { @@ -122,7 +122,7 @@ struct terminatingExtendedAreaDesc { uint8_t stdIdent[VSD_STD_ID_LEN]; uint8_t structVersion; uint8_t structData[2041]; -} __attribute__ ((packed)); +} __packed; /* Boot Descriptor (ECMA 167r3 2/9.4) */ struct bootDesc { @@ -140,7 +140,7 @@ struct bootDesc { __le16 flags; uint8_t reserved2[32]; uint8_t bootUse[1906]; -} __attribute__ ((packed)); +} __packed; /* Flags (ECMA 167r3 2/9.4.12) */ #define BOOT_FLAGS_ERASE 0x01 @@ -149,7 +149,7 @@ struct bootDesc { struct extent_ad { __le32 extLength; __le32 extLocation; -} __attribute__ ((packed)); +} __packed; struct kernel_extent_ad { uint32_t extLength; @@ -166,7 +166,7 @@ struct tag { __le16 descCRC; __le16 descCRCLength; __le32 tagLocation; -} __attribute__ ((packed)); +} __packed; /* Tag Identifier (ECMA 167r3 3/7.2.1) */ #define TAG_IDENT_PVD 0x0001 @@ -186,7 +186,7 @@ struct NSRDesc { uint8_t structVersion; uint8_t reserved; uint8_t structData[2040]; -} __attribute__ ((packed)); +} __packed; /* Primary Volume Descriptor (ECMA 167r3 3/10.1) */ struct primaryVolDesc { @@ -212,7 +212,7 @@ struct primaryVolDesc { __le32 predecessorVolDescSeqLocation; __le16 flags; uint8_t reserved[22]; -} __attribute__ ((packed)); +} __packed; /* Flags (ECMA 167r3 3/10.1.21) */ #define PVD_FLAGS_VSID_COMMON 0x0001 @@ -223,7 +223,7 @@ struct anchorVolDescPtr { struct extent_ad mainVolDescSeqExt; struct extent_ad reserveVolDescSeqExt; uint8_t reserved[480]; -} __attribute__ ((packed)); +} __packed; /* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */ struct volDescPtr { @@ -231,7 +231,7 @@ struct volDescPtr { __le32 volDescSeqNum; struct extent_ad nextVolDescSeqExt; uint8_t reserved[484]; -} __attribute__ ((packed)); +} __packed; /* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */ struct impUseVolDesc { @@ -239,7 +239,7 @@ struct impUseVolDesc { __le32 volDescSeqNum; struct regid impIdent; uint8_t impUse[460]; -} __attribute__ ((packed)); +} __packed; /* Partition Descriptor (ECMA 167r3 3/10.5) */ struct partitionDesc { @@ -255,7 +255,7 @@ struct partitionDesc { struct regid impIdent; uint8_t impUse[128]; uint8_t reserved[156]; -} __attribute__ ((packed)); +} __packed; /* Partition Flags (ECMA 167r3 3/10.5.3) */ #define PD_PARTITION_FLAGS_ALLOC 0x0001 @@ -291,14 +291,14 @@ struct logicalVolDesc { uint8_t impUse[128]; struct extent_ad integritySeqExt; uint8_t partitionMaps[0]; -} __attribute__ ((packed)); +} __packed; /* Generic Partition Map (ECMA 167r3 3/10.7.1) */ struct genericPartitionMap { uint8_t partitionMapType; uint8_t partitionMapLength; uint8_t partitionMapping[0]; -} __attribute__ ((packed)); +} __packed; /* Partition Map Type (ECMA 167r3 3/10.7.1.1) */ #define GP_PARTITION_MAP_TYPE_UNDEF 0x00 @@ -311,14 +311,14 @@ struct genericPartitionMap1 { uint8_t partitionMapLength; __le16 volSeqNum; __le16 partitionNum; -} __attribute__ ((packed)); +} __packed; /* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */ struct genericPartitionMap2 { uint8_t partitionMapType; uint8_t partitionMapLength; uint8_t partitionIdent[62]; -} __attribute__ ((packed)); +} __packed; /* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */ struct unallocSpaceDesc { @@ -326,13 +326,13 @@ struct unallocSpaceDesc { __le32 volDescSeqNum; __le32 numAllocDescs; struct extent_ad allocDescs[0]; -} __attribute__ ((packed)); +} __packed; /* Terminating Descriptor (ECMA 167r3 3/10.9) */ struct terminatingDesc { struct tag descTag; uint8_t reserved[496]; -} __attribute__ ((packed)); +} __packed; /* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */ struct logicalVolIntegrityDesc { @@ -346,7 +346,7 @@ struct logicalVolIntegrityDesc { __le32 freeSpaceTable[0]; __le32 sizeTable[0]; uint8_t impUse[0]; -} __attribute__ ((packed)); +} __packed; /* Integrity Type (ECMA 167r3 3/10.10.3) */ #define LVID_INTEGRITY_TYPE_OPEN 0x00000000 @@ -356,7 +356,7 @@ struct logicalVolIntegrityDesc { struct lb_addr { __le32 logicalBlockNum; __le16 partitionReferenceNum; -} __attribute__ ((packed)); +} __packed; /* ... and its in-core analog */ struct kernel_lb_addr { @@ -368,14 +368,14 @@ struct kernel_lb_addr { struct short_ad { __le32 extLength; __le32 extPosition; -} __attribute__ ((packed)); +} __packed; /* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */ struct long_ad { __le32 extLength; struct lb_addr extLocation; uint8_t impUse[6]; -} __attribute__ ((packed)); +} __packed; struct kernel_long_ad { uint32_t extLength; @@ -389,7 +389,7 @@ struct ext_ad { __le32 recordedLength; __le32 informationLength; struct lb_addr extLocation; -} __attribute__ ((packed)); +} __packed; struct kernel_ext_ad { uint32_t extLength; @@ -434,7 +434,7 @@ struct fileSetDesc { struct long_ad nextExt; struct long_ad streamDirectoryICB; uint8_t reserved[32]; -} __attribute__ ((packed)); +} __packed; /* Partition Header Descriptor (ECMA 167r3 4/14.3) */ struct partitionHeaderDesc { @@ -444,7 +444,7 @@ struct partitionHeaderDesc { struct short_ad freedSpaceTable; struct short_ad freedSpaceBitmap; uint8_t reserved[88]; -} __attribute__ ((packed)); +} __packed; /* File Identifier Descriptor (ECMA 167r3 4/14.4) */ struct fileIdentDesc { @@ -457,7 +457,7 @@ struct fileIdentDesc { uint8_t impUse[0]; uint8_t fileIdent[0]; uint8_t padding[0]; -} __attribute__ ((packed)); +} __packed; /* File Characteristics (ECMA 167r3 4/14.4.3) */ #define FID_FILE_CHAR_HIDDEN 0x01 @@ -471,7 +471,7 @@ struct allocExtDesc { struct tag descTag; __le32 previousAllocExtLocation; __le32 lengthAllocDescs; -} __attribute__ ((packed)); +} __packed; /* ICB Tag (ECMA 167r3 4/14.6) */ struct icbtag { @@ -483,7 +483,7 @@ struct icbtag { uint8_t fileType; struct lb_addr parentICBLocation; __le16 flags; -} __attribute__ ((packed)); +} __packed; /* Strategy Type (ECMA 167r3 4/14.6.2) */ #define ICBTAG_STRATEGY_TYPE_UNDEF 0x0000 @@ -531,13 +531,13 @@ struct indirectEntry { struct tag descTag; struct icbtag icbTag; struct long_ad indirectICB; -} __attribute__ ((packed)); +} __packed; /* Terminal Entry (ECMA 167r3 4/14.8) */ struct terminalEntry { struct tag descTag; struct icbtag icbTag; -} __attribute__ ((packed)); +} __packed; /* File Entry (ECMA 167r3 4/14.9) */ struct fileEntry { @@ -563,7 +563,7 @@ struct fileEntry { __le32 lengthAllocDescs; uint8_t extendedAttr[0]; uint8_t allocDescs[0]; -} __attribute__ ((packed)); +} __packed; /* Permissions (ECMA 167r3 4/14.9.5) */ #define FE_PERM_O_EXEC 0x00000001U @@ -607,7 +607,7 @@ struct extendedAttrHeaderDesc { struct tag descTag; __le32 impAttrLocation; __le32 appAttrLocation; -} __attribute__ ((packed)); +} __packed; /* Generic Format (ECMA 167r3 4/14.10.2) */ struct genericFormat { @@ -616,7 +616,7 @@ struct genericFormat { uint8_t reserved[3]; __le32 attrLength; uint8_t attrData[0]; -} __attribute__ ((packed)); +} __packed; /* Character Set Information (ECMA 167r3 4/14.10.3) */ struct charSetInfo { @@ -627,7 +627,7 @@ struct charSetInfo { __le32 escapeSeqLength; uint8_t charSetType; uint8_t escapeSeq[0]; -} __attribute__ ((packed)); +} __packed; /* Alternate Permissions (ECMA 167r3 4/14.10.4) */ struct altPerms { @@ -638,7 +638,7 @@ struct altPerms { __le16 ownerIdent; __le16 groupIdent; __le16 permission; -} __attribute__ ((packed)); +} __packed; /* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */ struct fileTimesExtAttr { @@ -649,7 +649,7 @@ struct fileTimesExtAttr { __le32 dataLength; __le32 fileTimeExistence; uint8_t fileTimes; -} __attribute__ ((packed)); +} __packed; /* FileTimeExistence (ECMA 167r3 4/14.10.5.6) */ #define FTE_CREATION 0x00000001 @@ -666,7 +666,7 @@ struct infoTimesExtAttr { __le32 dataLength; __le32 infoTimeExistence; uint8_t infoTimes[0]; -} __attribute__ ((packed)); +} __packed; /* Device Specification (ECMA 167r3 4/14.10.7) */ struct deviceSpec { @@ -678,7 +678,7 @@ struct deviceSpec { __le32 majorDeviceIdent; __le32 minorDeviceIdent; uint8_t impUse[0]; -} __attribute__ ((packed)); +} __packed; /* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */ struct impUseExtAttr { @@ -689,7 +689,7 @@ struct impUseExtAttr { __le32 impUseLength; struct regid impIdent; uint8_t impUse[0]; -} __attribute__ ((packed)); +} __packed; /* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */ struct appUseExtAttr { @@ -700,7 +700,7 @@ struct appUseExtAttr { __le32 appUseLength; struct regid appIdent; uint8_t appUse[0]; -} __attribute__ ((packed)); +} __packed; #define EXTATTR_CHAR_SET 1 #define EXTATTR_ALT_PERMS 3 @@ -716,7 +716,7 @@ struct unallocSpaceEntry { struct icbtag icbTag; __le32 lengthAllocDescs; uint8_t allocDescs[0]; -} __attribute__ ((packed)); +} __packed; /* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */ struct spaceBitmapDesc { @@ -724,7 +724,7 @@ struct spaceBitmapDesc { __le32 numOfBits; __le32 numOfBytes; uint8_t bitmap[0]; -} __attribute__ ((packed)); +} __packed; /* Partition Integrity Entry (ECMA 167r3 4/14.13) */ struct partitionIntegrityEntry { @@ -735,7 +735,7 @@ struct partitionIntegrityEntry { uint8_t reserved[175]; struct regid impIdent; uint8_t impUse[256]; -} __attribute__ ((packed)); +} __packed; /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */ @@ -753,7 +753,7 @@ struct partitionIntegrityEntry { struct logicalVolHeaderDesc { __le64 uniqueID; uint8_t reserved[24]; -} __attribute__ ((packed)); +} __packed; /* Path Component (ECMA 167r3 4/14.16.1) */ struct pathComponent { @@ -761,7 +761,7 @@ struct pathComponent { uint8_t lengthComponentIdent; __le16 componentFileVersionNum; dstring componentIdent[0]; -} __attribute__ ((packed)); +} __packed; /* File Entry (ECMA 167r3 4/14.17) */ struct extendedFileEntry { @@ -791,6 +791,6 @@ struct extendedFileEntry { __le32 lengthAllocDescs; uint8_t extendedAttr[0]; uint8_t allocDescs[0]; -} __attribute__ ((packed)); +} __packed; #endif /* _ECMA_167_H */ diff --git a/fs/udf/osta_udf.h b/fs/udf/osta_udf.h index fbff74654df2..a4da59e38b7f 100644 --- a/fs/udf/osta_udf.h +++ b/fs/udf/osta_udf.h @@ -70,17 +70,17 @@ struct UDFIdentSuffix { uint8_t OSClass; uint8_t OSIdentifier; uint8_t reserved[4]; -} __attribute__ ((packed)); +} __packed; struct impIdentSuffix { uint8_t OSClass; uint8_t OSIdentifier; uint8_t reserved[6]; -} __attribute__ ((packed)); +} __packed; struct appIdentSuffix { uint8_t impUse[8]; -} __attribute__ ((packed)); +} __packed; /* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */ /* Implementation Use (UDF 2.50 2.2.6.4) */ @@ -92,7 +92,7 @@ struct logicalVolIntegrityDescImpUse { __le16 minUDFWriteRev; __le16 maxUDFWriteRev; uint8_t impUse[0]; -} __attribute__ ((packed)); +} __packed; /* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */ /* Implementation Use (UDF 2.50 2.2.7.2) */ @@ -104,7 +104,7 @@ struct impUseVolDescImpUse { dstring LVInfo3[36]; struct regid impIdent; uint8_t impUse[128]; -} __attribute__ ((packed)); +} __packed; struct udfPartitionMap2 { uint8_t partitionMapType; @@ -113,7 +113,7 @@ struct udfPartitionMap2 { struct regid partIdent; __le16 volSeqNum; __le16 partitionNum; -} __attribute__ ((packed)); +} __packed; /* Virtual Partition Map (UDF 2.50 2.2.8) */ struct virtualPartitionMap { @@ -124,7 +124,7 @@ struct virtualPartitionMap { __le16 volSeqNum; __le16 partitionNum; uint8_t reserved2[24]; -} __attribute__ ((packed)); +} __packed; /* Sparable Partition Map (UDF 2.50 2.2.9) */ struct sparablePartitionMap { @@ -139,7 +139,7 @@ struct sparablePartitionMap { uint8_t reserved2[1]; __le32 sizeSparingTable; __le32 locSparingTable[4]; -} __attribute__ ((packed)); +} __packed; /* Metadata Partition Map (UDF 2.4.0 2.2.10) */ struct metadataPartitionMap { @@ -156,14 +156,14 @@ struct metadataPartitionMap { __le16 alignUnitSize; uint8_t flags; uint8_t reserved2[5]; -} __attribute__ ((packed)); +} __packed; /* Virtual Allocation Table (UDF 1.5 2.2.10) */ struct virtualAllocationTable15 { __le32 VirtualSector[0]; struct regid vatIdent; __le32 previousVATICBLoc; -} __attribute__ ((packed)); +} __packed; #define ICBTAG_FILE_TYPE_VAT15 0x00U @@ -181,7 +181,7 @@ struct virtualAllocationTable20 { __le16 reserved; uint8_t impUse[0]; __le32 vatEntry[0]; -} __attribute__ ((packed)); +} __packed; #define ICBTAG_FILE_TYPE_VAT20 0xF8U @@ -189,7 +189,7 @@ struct virtualAllocationTable20 { struct sparingEntry { __le32 origLocation; __le32 mappedLocation; -} __attribute__ ((packed)); +} __packed; struct sparingTable { struct tag descTag; @@ -199,7 +199,7 @@ struct sparingTable { __le32 sequenceNum; struct sparingEntry mapEntry[0]; -} __attribute__ ((packed)); +} __packed; /* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */ #define ICBTAG_FILE_TYPE_MAIN 0xFA @@ -210,7 +210,7 @@ struct sparingTable { struct allocDescImpUse { __le16 flags; uint8_t impUse[4]; -} __attribute__ ((packed)); +} __packed; #define AD_IU_EXT_ERASED 0x0001 @@ -222,7 +222,7 @@ struct allocDescImpUse { struct freeEaSpace { __le16 headerChecksum; uint8_t freeEASpace[0]; -} __attribute__ ((packed)); +} __packed; /* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */ struct DVDCopyrightImpUse { @@ -230,14 +230,14 @@ struct DVDCopyrightImpUse { uint8_t CGMSInfo; uint8_t dataType; uint8_t protectionSystemInfo[4]; -} __attribute__ ((packed)); +} __packed; /* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */ /* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */ struct freeAppEASpace { __le16 headerChecksum; uint8_t freeEASpace[0]; -} __attribute__ ((packed)); +} __packed; /* UDF Defined System Stream (UDF 2.50 3.3.7) */ #define UDF_ID_UNIQUE_ID "*UDF Unique ID Mapping Data" From 3cc6f8444a9d9e4a167c575e4da7b6c6d626501a Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:50 +0100 Subject: [PATCH 0299/1587] udf: use pointer for kernel_long_ad argument Having struct kernel_long_ad laarr[EXTENT_MERGE_SIZE] in all function arguments could be understood as by-value parameter. Use kernel_long_ad pointer for functions depending on inode_getblk() Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 5f643c93f564..8d8eda8379ca 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -57,14 +57,12 @@ static sector_t inode_getblk(struct inode *, sector_t, int *, int *); static int8_t udf_insert_aext(struct inode *, struct extent_position, struct kernel_lb_addr, uint32_t); static void udf_split_extents(struct inode *, int *, int, int, - struct kernel_long_ad[EXTENT_MERGE_SIZE], int *); + struct kernel_long_ad *, int *); static void udf_prealloc_extents(struct inode *, int, int, - struct kernel_long_ad[EXTENT_MERGE_SIZE], int *); -static void udf_merge_extents(struct inode *, - struct kernel_long_ad[EXTENT_MERGE_SIZE], int *); -static void udf_update_extents(struct inode *, - struct kernel_long_ad[EXTENT_MERGE_SIZE], int, int, - struct extent_position *); + struct kernel_long_ad *, int *); +static void udf_merge_extents(struct inode *, struct kernel_long_ad *, int *); +static void udf_update_extents(struct inode *, struct kernel_long_ad *, int, + int, struct extent_position *); static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); static void __udf_clear_extent_cache(struct inode *inode) @@ -896,8 +894,7 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, } static void udf_split_extents(struct inode *inode, int *c, int offset, - int newblocknum, - struct kernel_long_ad laarr[EXTENT_MERGE_SIZE], + int newblocknum, struct kernel_long_ad *laarr, int *endnum) { unsigned long blocksize = inode->i_sb->s_blocksize; @@ -961,7 +958,7 @@ static void udf_split_extents(struct inode *inode, int *c, int offset, } static void udf_prealloc_extents(struct inode *inode, int c, int lastblock, - struct kernel_long_ad laarr[EXTENT_MERGE_SIZE], + struct kernel_long_ad *laarr, int *endnum) { int start, length = 0, currlength = 0, i; @@ -1056,8 +1053,7 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock, } } -static void udf_merge_extents(struct inode *inode, - struct kernel_long_ad laarr[EXTENT_MERGE_SIZE], +static void udf_merge_extents(struct inode *inode, struct kernel_long_ad *laarr, int *endnum) { int i; @@ -1156,8 +1152,7 @@ static void udf_merge_extents(struct inode *inode, } } -static void udf_update_extents(struct inode *inode, - struct kernel_long_ad laarr[EXTENT_MERGE_SIZE], +static void udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, int startnum, int endnum, struct extent_position *epos) { From 02d4ca49fa222021988b2791c8efefd70d3228ac Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:51 +0100 Subject: [PATCH 0300/1587] udf: merge bh free Merge all bh free at one place. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 8d8eda8379ca..582d6b2f0d5f 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -745,11 +745,8 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, ~(inode->i_sb->s_blocksize - 1)); udf_write_aext(inode, &cur_epos, &eloc, elen, 1); } - brelse(prev_epos.bh); - brelse(cur_epos.bh); - brelse(next_epos.bh); newblock = udf_get_lb_pblock(inode->i_sb, &eloc, offset); - return newblock; + goto out_free; } /* Are we beyond EOF? */ @@ -772,11 +769,9 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, /* Create extents for the hole between EOF and offset */ ret = udf_do_extend_file(inode, &prev_epos, laarr, offset); if (ret < 0) { - brelse(prev_epos.bh); - brelse(cur_epos.bh); - brelse(next_epos.bh); *err = ret; - return 0; + newblock = 0; + goto out_free; } c = 0; offset = 0; @@ -839,11 +834,9 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, iinfo->i_location.partitionReferenceNum, goal, err); if (!newblocknum) { - brelse(prev_epos.bh); - brelse(cur_epos.bh); - brelse(next_epos.bh); *err = -ENOSPC; - return 0; + newblock = 0; + goto out_free; } if (isBeyondEOF) iinfo->i_lenExtents += inode->i_sb->s_blocksize; @@ -870,15 +863,11 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, * the new number of extents is less than the old number */ udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); - brelse(prev_epos.bh); - brelse(cur_epos.bh); - brelse(next_epos.bh); - newblock = udf_get_pblock(inode->i_sb, newblocknum, iinfo->i_location.partitionReferenceNum, 0); if (!newblock) { *err = -EIO; - return 0; + goto out_free; } *new = 1; iinfo->i_next_alloc_block = block; @@ -889,7 +878,10 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, udf_sync_inode(inode); else mark_inode_dirty(inode); - +out_free: + brelse(prev_epos.bh); + brelse(cur_epos.bh); + brelse(next_epos.bh); return newblock; } From bbc9abd239917b838d82d580be843395ceb9c36b Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:52 +0100 Subject: [PATCH 0301/1587] udf: remove unneeded line break Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 582d6b2f0d5f..ea8f544df5b8 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -2271,8 +2271,7 @@ int8_t inode_bmap(struct inode *inode, sector_t block, uint32_t *elen, sector_t *offset) { unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; - loff_t lbcount = 0, bcount = - (loff_t) block << blocksize_bits; + loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits; int8_t etype; struct udf_inode_info *iinfo; From d50c4dd5279b6a2b3ae2c66435ec5c9825b7cff3 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:53 +0100 Subject: [PATCH 0302/1587] udf: remove empty condition loc & 0x02 is empty since first git version in 2005 in udf_add_extendedattr() Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/misc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/udf/misc.c b/fs/udf/misc.c index 71d1c25f360d..3949c4bec3a3 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c @@ -141,8 +141,6 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, iinfo->i_lenEAttr += size; return (struct genericFormat *)&ea[offset]; } - if (loc & 0x02) - ; return NULL; } From 7ed0fbd7e3187cc24a47565afcf7fc1f46684755 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:54 +0100 Subject: [PATCH 0303/1587] udf: Factor out trimming of crtime Factor out trimming of crtime field. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index ea8f544df5b8..8cc5dbccebc7 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1612,6 +1612,14 @@ static int udf_sync_inode(struct inode *inode) return udf_update_inode(inode, 1); } +static void udf_adjust_time(struct udf_inode_info *iinfo, struct timespec time) +{ + if (iinfo->i_crtime.tv_sec > time.tv_sec || + (iinfo->i_crtime.tv_sec == time.tv_sec && + iinfo->i_crtime.tv_nsec > time.tv_nsec)) + iinfo->i_crtime = time; +} + static int udf_update_inode(struct inode *inode, int do_sync) { struct buffer_head *bh = NULL; @@ -1738,20 +1746,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) efe->objectSize = cpu_to_le64(inode->i_size); efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded); - if (iinfo->i_crtime.tv_sec > inode->i_atime.tv_sec || - (iinfo->i_crtime.tv_sec == inode->i_atime.tv_sec && - iinfo->i_crtime.tv_nsec > inode->i_atime.tv_nsec)) - iinfo->i_crtime = inode->i_atime; - - if (iinfo->i_crtime.tv_sec > inode->i_mtime.tv_sec || - (iinfo->i_crtime.tv_sec == inode->i_mtime.tv_sec && - iinfo->i_crtime.tv_nsec > inode->i_mtime.tv_nsec)) - iinfo->i_crtime = inode->i_mtime; - - if (iinfo->i_crtime.tv_sec > inode->i_ctime.tv_sec || - (iinfo->i_crtime.tv_sec == inode->i_ctime.tv_sec && - iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec)) - iinfo->i_crtime = inode->i_ctime; + udf_adjust_time(iinfo, inode->i_atime); + udf_adjust_time(iinfo, inode->i_mtime); + udf_adjust_time(iinfo, inode->i_ctime); udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime); udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime); From b31c9ed99ed17f9572ee8babf2e89f1f002a7cce Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:56 +0100 Subject: [PATCH 0304/1587] udf: remove next_epos from udf_update_extent_cache() udf_update_extent_cache() is only called from inode_bmap() with 1 for next_epos Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 8cc5dbccebc7..b6c652d34413 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -109,7 +109,7 @@ static int udf_read_extent_cache(struct inode *inode, loff_t bcount, /* Add extent to extent cache */ static void udf_update_extent_cache(struct inode *inode, loff_t estart, - struct extent_position *pos, int next_epos) + struct extent_position *pos) { struct udf_inode_info *iinfo = UDF_I(inode); @@ -118,19 +118,16 @@ static void udf_update_extent_cache(struct inode *inode, loff_t estart, __udf_clear_extent_cache(inode); if (pos->bh) get_bh(pos->bh); - memcpy(&iinfo->cached_extent.epos, pos, - sizeof(struct extent_position)); + memcpy(&iinfo->cached_extent.epos, pos, sizeof(struct extent_position)); iinfo->cached_extent.lstart = estart; - if (next_epos) - switch (iinfo->i_alloc_type) { - case ICBTAG_FLAG_AD_SHORT: - iinfo->cached_extent.epos.offset -= - sizeof(struct short_ad); - break; - case ICBTAG_FLAG_AD_LONG: - iinfo->cached_extent.epos.offset -= - sizeof(struct long_ad); - } + switch (iinfo->i_alloc_type) { + case ICBTAG_FLAG_AD_SHORT: + iinfo->cached_extent.epos.offset -= sizeof(struct short_ad); + break; + case ICBTAG_FLAG_AD_LONG: + iinfo->cached_extent.epos.offset -= sizeof(struct long_ad); + break; + } spin_unlock(&iinfo->i_extent_cache_lock); } @@ -2289,7 +2286,7 @@ int8_t inode_bmap(struct inode *inode, sector_t block, lbcount += *elen; } while (lbcount <= bcount); /* update extent cache */ - udf_update_extent_cache(inode, lbcount - *elen, pos, 1); + udf_update_extent_cache(inode, lbcount - *elen, pos); *offset = (bcount + *elen - lbcount) >> blocksize_bits; return etype; From 54bb60d53114b83473ba1c622be4cca9533b9827 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:57 +0100 Subject: [PATCH 0305/1587] udf: merge module informations in super.c Move all module attributes at the end of one file like other FS. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 4 ---- fs/udf/super.c | 9 ++++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index b6c652d34413..2296c8708052 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -43,10 +43,6 @@ #include "udf_i.h" #include "udf_sb.h" -MODULE_AUTHOR("Ben Fennema"); -MODULE_DESCRIPTION("Universal Disk Format Filesystem"); -MODULE_LICENSE("GPL"); - #define EXTENT_MERGE_SIZE 5 static umode_t udf_convert_permissions(struct fileEntry *); diff --git a/fs/udf/super.c b/fs/udf/super.c index 967ad8775af2..9256117ffa27 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -264,9 +264,6 @@ static void __exit exit_udf_fs(void) destroy_inodecache(); } -module_init(init_udf_fs) -module_exit(exit_udf_fs) - static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count) { struct udf_sb_info *sbi = UDF_SB(sb); @@ -2500,3 +2497,9 @@ static unsigned int udf_count_free(struct super_block *sb) return accum; } + +MODULE_AUTHOR("Ben Fennema"); +MODULE_DESCRIPTION("Universal Disk Format Filesystem"); +MODULE_LICENSE("GPL"); +module_init(init_udf_fs) +module_exit(exit_udf_fs) From 23bcda112f77da278898841615c7530c3e91a537 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:54:41 +0100 Subject: [PATCH 0306/1587] udf: atomically read inode size See i_size_read() comments in include/linux/fs.h Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/lowlevel.c | 2 +- fs/udf/super.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c index 6ad5a453af97..5c7ec121990d 100644 --- a/fs/udf/lowlevel.c +++ b/fs/udf/lowlevel.c @@ -58,7 +58,7 @@ unsigned long udf_get_last_block(struct super_block *sb) */ if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) || lblock == 0) - lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits; + lblock = i_size_read(bdev->bd_inode) >> sb->s_blocksize_bits; if (lblock) return lblock - 1; diff --git a/fs/udf/super.c b/fs/udf/super.c index 9256117ffa27..6b5a1a45a6c1 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1213,7 +1213,8 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) struct udf_inode_info *vati; uint32_t pos; struct virtualAllocationTable20 *vat20; - sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits; + sector_t blocks = i_size_read(sb->s_bdev->bd_inode) >> + sb->s_blocksize_bits; udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block); if (!sbi->s_vat_inode && @@ -1803,7 +1804,7 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block, if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && udf_fixed_to_variable(block) >= - sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) + i_size_read(sb->s_bdev->bd_inode) >> sb->s_blocksize_bits) return -EAGAIN; bh = udf_read_tagged(sb, block, block, &ident); @@ -1865,7 +1866,7 @@ static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock, last[last_count++] = *lastblock - 152; for (i = 0; i < last_count; i++) { - if (last[i] >= sb->s_bdev->bd_inode->i_size >> + if (last[i] >= i_size_read(sb->s_bdev->bd_inode) >> sb->s_blocksize_bits) continue; ret = udf_check_anchor_block(sb, last[i], fileset); From 1d82a56bc5bf820b7c65d8130b44c0bc101b546c Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:54:43 +0100 Subject: [PATCH 0307/1587] udf: check partition reference in udf_read_inode() We were checking block number without checking partition. sbi->s_partmaps[iloc->partitionReferenceNum] could lead to bad memory access. See udf_nfs_get_inode() path for instance. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 2296c8708052..8ec6b3df0bc7 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1277,6 +1277,12 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode) int ret = -EIO; reread: + if (iloc->partitionReferenceNum >= sbi->s_partitions) { + udf_debug("partition reference: %d > logical volume partitions: %d\n", + iloc->partitionReferenceNum, sbi->s_partitions); + return -EIO; + } + if (iloc->logicalBlockNum >= sbi->s_partmaps[iloc->partitionReferenceNum].s_partition_len) { udf_debug("block=%d, partition=%d out of range\n", From 9c6a3af003c06ef1efc5e243cdbab1be4cb90753 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 3 Jan 2017 18:04:27 +0100 Subject: [PATCH 0308/1587] spi: make falcon-spi bool Falcon spi accesses some ebu functions which are not exported and can not be accessed when build as module. Make this module bool instead. Signed-off-by: Hauke Mehrtens Acked-by: Thomas Langer Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ec4aa252d6e8..e3c256685235 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -263,7 +263,7 @@ config SPI_EP93XX mode. config SPI_FALCON - tristate "Falcon SPI controller support" + bool "Falcon SPI controller support" depends on SOC_FALCON help The external bus unit (EBU) found on the FALC-ON SoC has SPI From aa18da8b7ec57f6ff255634746aed6266a01b315 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 10 Jan 2017 09:41:43 +0100 Subject: [PATCH 0309/1587] libata: avoid global response buffer in atapi_qc_complete We only need to look at 4 bytes of the inquiry response for ATAPI devices. Instead of using the global ata_scsi_rbuf just use a a stack buffer. Also factor the fixup into it's own little helper function to make it more readable. Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 46 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 1f863e757ee4..031a77aae19d 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2873,6 +2873,26 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) DPRINTK("EXIT\n"); } +/* + * ATAPI devices typically report zero for their SCSI version, and sometimes + * deviate from the spec WRT response data format. If SCSI version is + * reported as zero like normal, then we make the following fixups: + * 1) Fake MMC-5 version, to indicate to the Linux scsi midlayer this is a + * modern device. + * 2) Ensure response data format / ATAPI information are always correct. + */ +static void atapi_fixup_inquiry(struct scsi_cmnd *cmd) +{ + u8 buf[4]; + + sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, 4); + if (buf[2] == 0) { + buf[2] = 0x5; + buf[3] = 0x32; + } + sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, 4); +} + static void atapi_qc_complete(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; @@ -2927,30 +2947,8 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) */ ata_gen_passthru_sense(qc); } else { - u8 *scsicmd = cmd->cmnd; - - if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) { - unsigned long flags; - u8 *buf; - - buf = ata_scsi_rbuf_get(cmd, true, &flags); - - /* ATAPI devices typically report zero for their SCSI version, - * and sometimes deviate from the spec WRT response data - * format. If SCSI version is reported as zero like normal, - * then we make the following fixups: 1) Fake MMC-5 version, - * to indicate to the Linux scsi midlayer this is a modern - * device. 2) Ensure response data format / ATAPI information - * are always correct. - */ - if (buf[2] == 0) { - buf[2] = 0x5; - buf[3] = 0x32; - } - - ata_scsi_rbuf_put(cmd, true, &flags); - } - + if (cmd->cmnd[0] == INQUIRY && (cmd->cmnd[1] & 0x03) == 0) + atapi_fixup_inquiry(cmd); cmd->result = SAM_STAT_GOOD; } From f0a37d12f51a51d61f68dd30123f2b1927b56bb6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 10 Jan 2017 09:41:44 +0100 Subject: [PATCH 0310/1587] libata: move struct ata_scsi_args to libata-scsi.c It's only used in libata-scsi.c, so move it closer to the users. Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 7 +++++++ drivers/ata/libata.h | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 031a77aae19d..43694f5f2c89 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2057,6 +2057,13 @@ defer: return SCSI_MLQUEUE_HOST_BUSY; } +struct ata_scsi_args { + struct ata_device *dev; + u16 *id; + struct scsi_cmnd *cmd; + void (*done)(struct scsi_cmnd *); +}; + /** * ata_scsi_rbuf_get - Map response buffer. * @cmd: SCSI command containing buffer to be mapped. diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 1133e9439f9c..bba39a62552b 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -31,13 +31,6 @@ #define DRV_NAME "libata" #define DRV_VERSION "3.00" /* must be exactly four chars */ -struct ata_scsi_args { - struct ata_device *dev; - u16 *id; - struct scsi_cmnd *cmd; - void (*done)(struct scsi_cmnd *); -}; - /* libata-core.c */ enum { /* flags for ata_dev_read_id() */ From 506db3609cdf30b0ff661e8e38e95e91c54fbb82 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 10 Jan 2017 09:41:45 +0100 Subject: [PATCH 0311/1587] libata: remove the done callback from ata_scsi_args It's always the scsi_done callback, and we can get at that easily in the place where ->done is called. Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 43694f5f2c89..28e2530b9cd3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2061,7 +2061,6 @@ struct ata_scsi_args { struct ata_device *dev; u16 *id; struct scsi_cmnd *cmd; - void (*done)(struct scsi_cmnd *); }; /** @@ -2140,7 +2139,7 @@ static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, if (rc == 0) cmd->result = SAM_STAT_GOOD; - args->done(cmd); + cmd->scsi_done(cmd); } /** @@ -4357,7 +4356,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) args.dev = dev; args.id = dev->id; args.cmd = cmd; - args.done = cmd->scsi_done; switch(scsicmd[0]) { case INQUIRY: From 8fc6c0657bf852766f08d389c5c3378a032b3de7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 10 Jan 2017 09:41:46 +0100 Subject: [PATCH 0312/1587] libata: call ->scsi_done from ata_scsi_simulate We always need to call ->scsi_done after we've finished emulating a command, so do it in a single place at the end of ata_scsi_simulate. Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 28e2530b9cd3..6078bc28b325 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -484,13 +484,6 @@ struct device_attribute *ata_common_sdev_attrs[] = { }; EXPORT_SYMBOL_GPL(ata_common_sdev_attrs); -static void ata_scsi_invalid_field(struct ata_device *dev, - struct scsi_cmnd *cmd, u16 field) -{ - ata_scsi_set_invalid_field(dev, cmd, field, 0xff); - cmd->scsi_done(cmd); -} - /** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. * @sdev: SCSI device for which BIOS geometry is to be determined @@ -2139,7 +2132,6 @@ static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, if (rc == 0) cmd->result = SAM_STAT_GOOD; - cmd->scsi_done(cmd); } /** @@ -4360,7 +4352,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) switch(scsicmd[0]) { case INQUIRY: if (scsicmd[1] & 2) /* is CmdDt set? */ - ata_scsi_invalid_field(dev, cmd, 1); + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); else switch (scsicmd[2]) { @@ -4392,7 +4384,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) } /* Fallthrough */ default: - ata_scsi_invalid_field(dev, cmd, 2); + ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); break; } break; @@ -4410,7 +4402,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); else - ata_scsi_invalid_field(dev, cmd, 1); + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); break; case REPORT_LUNS: @@ -4420,7 +4412,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) case REQUEST_SENSE: ata_scsi_set_sense(dev, cmd, 0, 0, 0); cmd->result = (DRIVER_SENSE << 24); - cmd->scsi_done(cmd); break; /* if we reach this, then writeback caching is disabled, @@ -4442,23 +4433,24 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) ata_scsi_rbuf_fill(&args, ata_scsiop_noop); else - ata_scsi_invalid_field(dev, cmd, 1); + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); break; case MAINTENANCE_IN: if (scsicmd[1] == MI_REPORT_SUPPORTED_OPERATION_CODES) ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in); else - ata_scsi_invalid_field(dev, cmd, 1); + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); break; /* all other commands */ default: ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0); /* "Invalid command operation code" */ - cmd->scsi_done(cmd); break; } + + cmd->scsi_done(cmd); } int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) From a0c0b0e945cad4d6b2871469883fbbc316afcd44 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 10 Jan 2017 09:41:47 +0100 Subject: [PATCH 0313/1587] libata: don't call ata_scsi_rbuf_fill for command without a response buffer No need to copy a zeroed buffer to the caller if the command is defined to not have a response in the SCSI spec. Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 6078bc28b325..395c8591980f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2452,23 +2452,6 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf) return 0; } -/** - * ata_scsiop_noop - Command handler that simply returns success. - * @args: device IDENTIFY data / SCSI command of interest. - * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * - * No operation. Simply returns success to caller, to indicate - * that the caller should successfully complete this SCSI command. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf) -{ - VPRINTK("ENTER\n"); - return 0; -} - /** * modecpy - Prepare response for MODE SENSE * @dest: output buffer @@ -4425,14 +4408,11 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) case SEEK_6: case SEEK_10: case TEST_UNIT_READY: - ata_scsi_rbuf_fill(&args, ata_scsiop_noop); break; case SEND_DIAGNOSTIC: tmp8 = scsicmd[1] & ~(1 << 3); - if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) - ata_scsi_rbuf_fill(&args, ata_scsiop_noop); - else + if (tmp8 != 0x4 || scsicmd[3] || scsicmd[4]) ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); break; From a234f7395c9301a5048cb2daa4c86f15c6f02de8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 10 Jan 2017 17:04:32 +0100 Subject: [PATCH 0314/1587] libata: switch to dynamic allocation instead of ata_scsi_rbuf Note of the emulated commands in the pageout/pagein path, so just do a GFP_NOIO dynamic allocation. Signed-off-by: Christoph Hellwig Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 122 +++++++++++--------------------------- 1 file changed, 36 insertions(+), 86 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 395c8591980f..4de273b77abc 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -57,9 +57,6 @@ #define ATA_SCSI_RBUF_SIZE 4096 -static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); -static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE]; - typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc); static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, @@ -2056,53 +2053,6 @@ struct ata_scsi_args { struct scsi_cmnd *cmd; }; -/** - * ata_scsi_rbuf_get - Map response buffer. - * @cmd: SCSI command containing buffer to be mapped. - * @flags: unsigned long variable to store irq enable status - * @copy_in: copy in from user buffer - * - * Prepare buffer for simulated SCSI commands. - * - * LOCKING: - * spin_lock_irqsave(ata_scsi_rbuf_lock) on success - * - * RETURNS: - * Pointer to response buffer. - */ -static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in, - unsigned long *flags) -{ - spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags); - - memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); - if (copy_in) - sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), - ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); - return ata_scsi_rbuf; -} - -/** - * ata_scsi_rbuf_put - Unmap response buffer. - * @cmd: SCSI command containing buffer to be unmapped. - * @copy_out: copy out result - * @flags: @flags passed to ata_scsi_rbuf_get() - * - * Returns rbuf buffer. The result is copied to @cmd's buffer if - * @copy_back is true. - * - * LOCKING: - * Unlocks ata_scsi_rbuf_lock. - */ -static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out, - unsigned long *flags) -{ - if (copy_out) - sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), - ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); - spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags); -} - /** * ata_scsi_rbuf_fill - wrapper for SCSI command simulators * @args: device IDENTIFY data / SCSI command of interest. @@ -2121,17 +2071,22 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out, static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf)) { - u8 *rbuf; - unsigned int rc; struct scsi_cmnd *cmd = args->cmd; - unsigned long flags; + u8 *buf; - rbuf = ata_scsi_rbuf_get(cmd, false, &flags); - rc = actor(args, rbuf); - ata_scsi_rbuf_put(cmd, rc == 0, &flags); + buf = kzalloc(ATA_SCSI_RBUF_SIZE, GFP_NOIO); + if (!buf) { + ata_scsi_set_sense(args->dev, cmd, NOT_READY, 0x08, 0); + return; + } - if (rc == 0) + if (actor(args, buf) == 0) { + sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), + buf, ATA_SCSI_RBUF_SIZE); cmd->result = SAM_STAT_GOOD; + } + + kfree(buf); } /** @@ -3363,24 +3318,17 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * * Return: Number of bytes copied into sglist. */ -static size_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax, +static ssize_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax, u64 sector, u32 count) { - struct scsi_device *sdp = cmd->device; - size_t len = sdp->sector_size; size_t r; __le64 *buf; u32 i = 0; - unsigned long flags; - WARN_ON(len > ATA_SCSI_RBUF_SIZE); + buf = kzalloc(cmd->device->sector_size, GFP_NOFS); + if (!buf) + return -ENOMEM; - if (len > ATA_SCSI_RBUF_SIZE) - len = ATA_SCSI_RBUF_SIZE; - - spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); - buf = ((void *)ata_scsi_rbuf); - memset(buf, 0, len); while (i < trmax) { u64 entry = sector | ((u64)(count > 0xffff ? 0xffff : count) << 48); @@ -3390,9 +3338,9 @@ static size_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax, count -= 0xffff; sector += 0xffff; } - r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len); - spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); - + r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, + cmd->device->sector_size); + kfree(buf); return r; } @@ -3408,16 +3356,15 @@ static size_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax, * * Return: Number of bytes copied into sglist. */ -static size_t ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num) +static ssize_t ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, + u64 num) { - struct scsi_device *sdp = cmd->device; - size_t len = sdp->sector_size; size_t r; u16 *buf; - unsigned long flags; - spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); - buf = ((void *)ata_scsi_rbuf); + buf = kzalloc(cmd->device->sector_size, GFP_NOIO); + if (!buf) + return -ENOMEM; put_unaligned_le16(0x0002, &buf[0]); /* SCT_ACT_WRITE_SAME */ put_unaligned_le16(0x0101, &buf[1]); /* WRITE PTRN FG */ @@ -3425,14 +3372,9 @@ static size_t ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num) put_unaligned_le64(num, &buf[6]); put_unaligned_le32(0u, &buf[10]); /* pattern */ - WARN_ON(len > ATA_SCSI_RBUF_SIZE); - - if (len > ATA_SCSI_RBUF_SIZE) - len = ATA_SCSI_RBUF_SIZE; - - r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len); - spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); - + r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, + cmd->device->sector_size); + kfree(buf); return r; } @@ -3457,7 +3399,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) u64 block; u32 n_block; const u32 trmax = len >> 3; - u32 size; + ssize_t size; u16 fp; u8 bp = 0xff; u8 unmap = cdb[1] & 0x8; @@ -3508,6 +3450,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) */ if (unmap) { size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block); + if (size < 0) + goto comm_fail; if (size != len) goto invalid_param_len; @@ -3531,6 +3475,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) } } else { size = ata_format_sct_write_same(scmd, block, n_block); + if (size < 0) + goto comm_fail; if (size != len) goto invalid_param_len; @@ -3569,6 +3515,10 @@ invalid_opcode: /* "Invalid command operation code" */ ata_scsi_set_sense(dev, scmd, ILLEGAL_REQUEST, 0x20, 0x0); return 1; +comm_fail: + /* "Logical unit communication failure" */ + ata_scsi_set_sense(dev, scmd, NOT_READY, 0x08, 0); + return 1; } /** From 7563f625469e9488fcd23cb64f9a6d61f1758f47 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 30 Dec 2016 15:01:16 +0100 Subject: [PATCH 0315/1587] ata: allow subsystem to be used on m68k arch When libata was merged m68k lacked IOMAP support. This has not been true for a long time now so allow subsystem to be used on m68k. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 38318aaf29d3..702b3514020c 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -14,7 +14,7 @@ menuconfig ATA tristate "Serial ATA and Parallel ATA drivers (libata)" depends on HAS_IOMEM depends on BLOCK - depends on !(M32R || M68K || S390) || BROKEN + depends on !(M32R || S390) || BROKEN select SCSI select GLOB ---help--- From 989e0aac1a801e9e9580632c9fd448a7aaca596a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 30 Dec 2016 15:01:17 +0100 Subject: [PATCH 0316/1587] ata: pass queued command to ->sff_data_xfer method For Atari Falcon PATA support we need to check the current command in its ->sff_data_xfer method. Update core code and all users accordingly. There should be no functional changes caused by this patch. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tejun Heo --- drivers/ata/libata-sff.c | 29 +++++++++++++++-------------- drivers/ata/pata_at91.c | 6 +++--- drivers/ata/pata_bf54x.c | 7 ++++--- drivers/ata/pata_ep93xx.c | 4 ++-- drivers/ata/pata_ixp4xx_cf.c | 4 ++-- drivers/ata/pata_legacy.c | 15 +++++++++------ drivers/ata/pata_octeon_cf.c | 12 ++++++------ drivers/ata/pata_pcmcia.c | 6 +++--- drivers/ata/pata_samsung_cf.c | 4 ++-- drivers/ata/sata_rcar.c | 4 ++-- include/linux/libata.h | 8 ++++---- 11 files changed, 52 insertions(+), 47 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 051b6158d1b7..4441b5c5e4fb 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -542,7 +542,7 @@ static inline void ata_tf_to_host(struct ata_port *ap, /** * ata_sff_data_xfer - Transfer data by PIO - * @dev: device to target + * @qc: queued command * @buf: data buffer * @buflen: buffer length * @rw: read/write @@ -555,10 +555,10 @@ static inline void ata_tf_to_host(struct ata_port *ap, * RETURNS: * Bytes consumed. */ -unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, +unsigned int ata_sff_data_xfer(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = qc->dev->link->ap; void __iomem *data_addr = ap->ioaddr.data_addr; unsigned int words = buflen >> 1; @@ -595,7 +595,7 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer); /** * ata_sff_data_xfer32 - Transfer data by PIO - * @dev: device to target + * @qc: queued command * @buf: data buffer * @buflen: buffer length * @rw: read/write @@ -610,16 +610,17 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer); * Bytes consumed. */ -unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf, +unsigned int ata_sff_data_xfer32(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { + struct ata_device *dev = qc->dev; struct ata_port *ap = dev->link->ap; void __iomem *data_addr = ap->ioaddr.data_addr; unsigned int words = buflen >> 2; int slop = buflen & 3; if (!(ap->pflags & ATA_PFLAG_PIO32)) - return ata_sff_data_xfer(dev, buf, buflen, rw); + return ata_sff_data_xfer(qc, buf, buflen, rw); /* Transfer multiple of 4 bytes */ if (rw == READ) @@ -658,7 +659,7 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer32); /** * ata_sff_data_xfer_noirq - Transfer data by PIO - * @dev: device to target + * @qc: queued command * @buf: data buffer * @buflen: buffer length * @rw: read/write @@ -672,14 +673,14 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer32); * RETURNS: * Bytes consumed. */ -unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, +unsigned int ata_sff_data_xfer_noirq(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { unsigned long flags; unsigned int consumed; local_irq_save(flags); - consumed = ata_sff_data_xfer32(dev, buf, buflen, rw); + consumed = ata_sff_data_xfer32(qc, buf, buflen, rw); local_irq_restore(flags); return consumed; @@ -723,14 +724,14 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) buf = kmap_atomic(page); /* do the actual data transfer */ - ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size, + ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size, do_write); kunmap_atomic(buf); local_irq_restore(flags); } else { buf = page_address(page); - ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size, + ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size, do_write); } @@ -791,7 +792,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) DPRINTK("send cdb\n"); WARN_ON_ONCE(qc->dev->cdb_len < 12); - ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); + ap->ops->sff_data_xfer(qc, qc->cdb, qc->dev->cdb_len, 1); ata_sff_sync(ap); /* FIXME: If the CDB is for DMA do we need to do the transition delay or is bmdma_start guaranteed to do it ? */ @@ -868,14 +869,14 @@ next_sg: buf = kmap_atomic(page); /* do the actual data transfer */ - consumed = ap->ops->sff_data_xfer(dev, buf + offset, + consumed = ap->ops->sff_data_xfer(qc, buf + offset, count, rw); kunmap_atomic(buf); local_irq_restore(flags); } else { buf = page_address(page); - consumed = ap->ops->sff_data_xfer(dev, buf + offset, + consumed = ap->ops->sff_data_xfer(qc, buf + offset, count, rw); } diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index 1611e0e8d767..fd5b34f0d007 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -286,10 +286,10 @@ static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev) set_smc_timing(ap->dev, adev, info, &timing); } -static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev, +static unsigned int pata_at91_data_xfer_noirq(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { - struct at91_ide_info *info = dev->link->ap->host->private_data; + struct at91_ide_info *info = qc->dev->link->ap->host->private_data; unsigned int consumed; unsigned int mode; unsigned long flags; @@ -301,7 +301,7 @@ static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev, regmap_fields_write(fields.mode, info->cs, (mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_16); - consumed = ata_sff_data_xfer(dev, buf, buflen, rw); + consumed = ata_sff_data_xfer(qc, buf, buflen, rw); /* restore 8bit mode after data is written */ regmap_fields_write(fields.mode, info->cs, (mode & ~AT91_SMC_DBW) | diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index ec748d31928d..9c5780a7e1b9 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1143,7 +1143,7 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap) /** * bfin_data_xfer - Transfer data by PIO - * @adev: device for this I/O + * @qc: queued command * @buf: data buffer * @buflen: buffer length * @write_data: read/write @@ -1151,10 +1151,11 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap) * Note: Original code is ata_sff_data_xfer(). */ -static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf, +static unsigned int bfin_data_xfer(struct ata_queued_cmd *qc, + unsigned char *buf, unsigned int buflen, int rw) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = qc->dev->link->ap; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; unsigned int words = buflen >> 1; unsigned short *buf16 = (u16 *)buf; diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index bd6b089c67a3..bf1b910c5d69 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -474,11 +474,11 @@ static void ep93xx_pata_set_devctl(struct ata_port *ap, u8 ctl) } /* Note: original code is ata_sff_data_xfer */ -static unsigned int ep93xx_pata_data_xfer(struct ata_device *adev, +static unsigned int ep93xx_pata_data_xfer(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { - struct ata_port *ap = adev->link->ap; + struct ata_port *ap = qc->dev->link->ap; struct ep93xx_pata_data *drv_data = ap->host->private_data; u16 *data = (u16 *)buf; unsigned int words = buflen >> 1; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index abda44183512..0b0d93065f5a 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -40,13 +40,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) return 0; } -static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev, +static unsigned int ixp4xx_mmio_data_xfer(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { unsigned int i; unsigned int words = buflen >> 1; u16 *buf16 = (u16 *) buf; - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = qc->dev->link->ap; void __iomem *mmio = ap->ioaddr.data_addr; struct ixp4xx_pata_data *data = dev_get_platdata(ap->host->dev); diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index bce2a8ca4678..53828b6c3044 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -303,11 +303,12 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) } -static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, +static unsigned int pdc_data_xfer_vlb(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { - int slop = buflen & 3; + struct ata_device *dev = qc->dev; struct ata_port *ap = dev->link->ap; + int slop = buflen & 3; /* 32bit I/O capable *and* we need to write a whole number of dwords */ if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3) @@ -340,7 +341,7 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, } local_irq_restore(flags); } else - buflen = ata_sff_data_xfer_noirq(dev, buf, buflen, rw); + buflen = ata_sff_data_xfer_noirq(qc, buf, buflen, rw); return buflen; } @@ -702,9 +703,11 @@ static unsigned int qdi_qc_issue(struct ata_queued_cmd *qc) return ata_sff_qc_issue(qc); } -static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int rw) +static unsigned int vlb32_data_xfer(struct ata_queued_cmd *qc, + unsigned char *buf, + unsigned int buflen, int rw) { + struct ata_device *adev = qc->dev; struct ata_port *ap = adev->link->ap; int slop = buflen & 3; @@ -727,7 +730,7 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf, } return (buflen + 3) & ~3; } else - return ata_sff_data_xfer(adev, buf, buflen, rw); + return ata_sff_data_xfer(qc, buf, buflen, rw); } static int qdi_port(struct platform_device *dev, diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index 475a00669427..e94e7ca0e743 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -293,17 +293,17 @@ static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev) /** * Handle an 8 bit I/O request. * - * @dev: Device to access + * @qc: Queued command * @buffer: Data buffer * @buflen: Length of the buffer. * @rw: True to write. */ -static unsigned int octeon_cf_data_xfer8(struct ata_device *dev, +static unsigned int octeon_cf_data_xfer8(struct ata_queued_cmd *qc, unsigned char *buffer, unsigned int buflen, int rw) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = qc->dev->link->ap; void __iomem *data_addr = ap->ioaddr.data_addr; unsigned long words; int count; @@ -332,17 +332,17 @@ static unsigned int octeon_cf_data_xfer8(struct ata_device *dev, /** * Handle a 16 bit I/O request. * - * @dev: Device to access + * @qc: Queued command * @buffer: Data buffer * @buflen: Length of the buffer. * @rw: True to write. */ -static unsigned int octeon_cf_data_xfer16(struct ata_device *dev, +static unsigned int octeon_cf_data_xfer16(struct ata_queued_cmd *qc, unsigned char *buffer, unsigned int buflen, int rw) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = qc->dev->link->ap; void __iomem *data_addr = ap->ioaddr.data_addr; unsigned long words; int count; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index bcc4b968c049..a541eacc5e95 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -90,7 +90,7 @@ static int pcmcia_set_mode_8bit(struct ata_link *link, /** * ata_data_xfer_8bit - Transfer data by 8bit PIO - * @dev: device to target + * @qc: queued command * @buf: data buffer * @buflen: buffer length * @rw: read/write @@ -101,10 +101,10 @@ static int pcmcia_set_mode_8bit(struct ata_link *link, * Inherited from caller. */ -static unsigned int ata_data_xfer_8bit(struct ata_device *dev, +static unsigned int ata_data_xfer_8bit(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = qc->dev->link->ap; if (rw == READ) ioread8_rep(ap->ioaddr.data_addr, buf, buflen); diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index f6facd686f94..431c7de30ce6 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -263,10 +263,10 @@ static u8 pata_s3c_check_altstatus(struct ata_port *ap) /* * pata_s3c_data_xfer - Transfer data by PIO */ -static unsigned int pata_s3c_data_xfer(struct ata_device *dev, +static unsigned int pata_s3c_data_xfer(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = qc->dev->link->ap; struct s3c_ide_info *info = ap->host->private_data; void __iomem *data_addr = ap->ioaddr.data_addr; unsigned int words = buflen >> 1, i; diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index f72d601e300a..5d38245a7a73 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -447,11 +447,11 @@ static void sata_rcar_exec_command(struct ata_port *ap, ata_sff_pause(ap); } -static unsigned int sata_rcar_data_xfer(struct ata_device *dev, +static unsigned int sata_rcar_data_xfer(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = qc->dev->link->ap; void __iomem *data_addr = ap->ioaddr.data_addr; unsigned int words = buflen >> 1; diff --git a/include/linux/libata.h b/include/linux/libata.h index c170be548b7f..0e8a8000b45f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -968,7 +968,7 @@ struct ata_port_operations { void (*sff_tf_read)(struct ata_port *ap, struct ata_taskfile *tf); void (*sff_exec_command)(struct ata_port *ap, const struct ata_taskfile *tf); - unsigned int (*sff_data_xfer)(struct ata_device *dev, + unsigned int (*sff_data_xfer)(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw); void (*sff_irq_on)(struct ata_port *); bool (*sff_irq_check)(struct ata_port *); @@ -1823,11 +1823,11 @@ extern void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); extern void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf); extern void ata_sff_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); -extern unsigned int ata_sff_data_xfer(struct ata_device *dev, +extern unsigned int ata_sff_data_xfer(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw); -extern unsigned int ata_sff_data_xfer32(struct ata_device *dev, +extern unsigned int ata_sff_data_xfer32(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw); -extern unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, +extern unsigned int ata_sff_data_xfer_noirq(struct ata_queued_cmd *qc, unsigned char *buf, unsigned int buflen, int rw); extern void ata_sff_irq_on(struct ata_port *ap); extern void ata_sff_irq_clear(struct ata_port *ap); From 7e11aabd48eb00240b280bf927cba9198664dcf6 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 30 Dec 2016 15:01:18 +0100 Subject: [PATCH 0317/1587] ata: add Atari Falcon PATA controller driver Add Atari Falcon PATA controller driver. The major difference when compared to legacy IDE's falconide host driver is that we are using polled PIO mode and thus avoiding the need for STDMA locking magic altogether. Tested under ARAnyM emulator. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 1 + drivers/ata/pata_falcon.c | 184 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 drivers/ata/pata_falcon.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 702b3514020c..78c002021029 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -902,6 +902,15 @@ config PATA_CMD640_PCI If unsure, say N. +config PATA_FALCON + tristate "Atari Falcon PATA support" + depends on M68K && ATARI + help + This option enables support for the on-board IDE + interface on the Atari Falcon. + + If unsure, say N. + config PATA_ISAPNP tristate "ISA Plug and Play PATA support" depends on ISAPNP diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index a46e6b784bda..89a0a1915d36 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o obj-$(CONFIG_PATA_AT32) += pata_at32.o obj-$(CONFIG_PATA_AT91) += pata_at91.o obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o +obj-$(CONFIG_PATA_FALCON) += pata_falcon.o obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o diff --git a/drivers/ata/pata_falcon.c b/drivers/ata/pata_falcon.c new file mode 100644 index 000000000000..78264082a4cf --- /dev/null +++ b/drivers/ata/pata_falcon.c @@ -0,0 +1,184 @@ +/* + * Atari Falcon PATA controller driver + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Based on falconide.c: + * + * Created 12 Jul 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_falcon" +#define DRV_VERSION "0.1.0" + +#define ATA_HD_BASE 0xfff00000 +#define ATA_HD_CONTROL 0x39 + +static struct scsi_host_template pata_falcon_sht = { + ATA_PIO_SHT(DRV_NAME), +}; + +static unsigned int pata_falcon_data_xfer(struct ata_queued_cmd *qc, + unsigned char *buf, + unsigned int buflen, int rw) +{ + struct ata_device *dev = qc->dev; + struct ata_port *ap = dev->link->ap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + struct scsi_cmnd *cmd = qc->scsicmd; + bool swap = 1; + + if (dev->class == ATA_DEV_ATA && cmd && cmd->request && + cmd->request->cmd_type == REQ_TYPE_FS) + swap = 0; + + /* Transfer multiple of 2 bytes */ + if (rw == READ) { + if (swap) + raw_insw_swapw((u16 *)data_addr, (u16 *)buf, words); + else + raw_insw((u16 *)data_addr, (u16 *)buf, words); + } else { + if (swap) + raw_outsw_swapw((u16 *)data_addr, (u16 *)buf, words); + else + raw_outsw((u16 *)data_addr, (u16 *)buf, words); + } + + /* Transfer trailing byte, if any. */ + if (unlikely(buflen & 0x01)) { + unsigned char pad[2] = { }; + + /* Point buf to the tail of buffer */ + buf += buflen - 1; + + if (rw == READ) { + if (swap) + raw_insw_swapw((u16 *)data_addr, (u16 *)pad, 1); + else + raw_insw((u16 *)data_addr, (u16 *)pad, 1); + *buf = pad[0]; + } else { + pad[0] = *buf; + if (swap) + raw_outsw_swapw((u16 *)data_addr, (u16 *)pad, 1); + else + raw_outsw((u16 *)data_addr, (u16 *)pad, 1); + } + words++; + } + + return words << 1; +} + +/* + * Provide our own set_mode() as we don't want to change anything that has + * already been configured.. + */ +static int pata_falcon_set_mode(struct ata_link *link, + struct ata_device **unused) +{ + struct ata_device *dev; + + ata_for_each_dev(dev, link, ENABLED) { + /* We don't really care */ + dev->pio_mode = dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; + ata_dev_info(dev, "configured for PIO\n"); + } + return 0; +} + +static struct ata_port_operations pata_falcon_ops = { + .inherits = &ata_sff_port_ops, + .sff_data_xfer = pata_falcon_data_xfer, + .cable_detect = ata_cable_unknown, + .set_mode = pata_falcon_set_mode, +}; + +static int pata_falcon_init_one(void) +{ + struct ata_host *host; + struct ata_port *ap; + struct platform_device *pdev; + void __iomem *base; + + if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE)) + return -ENODEV; + + pr_info(DRV_NAME ": Atari Falcon PATA controller\n"); + + pdev = platform_device_register_simple(DRV_NAME, 0, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + if (!devm_request_mem_region(&pdev->dev, ATA_HD_BASE, 0x40, DRV_NAME)) { + pr_err(DRV_NAME ": resources busy\n"); + return -EBUSY; + } + + /* allocate host */ + host = ata_host_alloc(&pdev->dev, 1); + if (!host) + return -ENOMEM; + ap = host->ports[0]; + + ap->ops = &pata_falcon_ops; + ap->pio_mask = ATA_PIO4; + ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY; + ap->flags |= ATA_FLAG_PIO_POLLING; + + base = (void __iomem *)ATA_HD_BASE; + ap->ioaddr.data_addr = base; + ap->ioaddr.error_addr = base + 1 + 1 * 4; + ap->ioaddr.feature_addr = base + 1 + 1 * 4; + ap->ioaddr.nsect_addr = base + 1 + 2 * 4; + ap->ioaddr.lbal_addr = base + 1 + 3 * 4; + ap->ioaddr.lbam_addr = base + 1 + 4 * 4; + ap->ioaddr.lbah_addr = base + 1 + 5 * 4; + ap->ioaddr.device_addr = base + 1 + 6 * 4; + ap->ioaddr.status_addr = base + 1 + 7 * 4; + ap->ioaddr.command_addr = base + 1 + 7 * 4; + + ap->ioaddr.altstatus_addr = base + ATA_HD_CONTROL; + ap->ioaddr.ctl_addr = base + ATA_HD_CONTROL; + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", (unsigned long)base, + (unsigned long)base + ATA_HD_CONTROL); + + /* activate */ + return ata_host_activate(host, 0, NULL, 0, &pata_falcon_sht); +} + +module_init(pata_falcon_init_one); + +MODULE_AUTHOR("Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("low-level driver for Atari Falcon PATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); From 3c7ce3427106f0fa2d8593f9fd8f82c494215782 Mon Sep 17 00:00:00 2001 From: Vishal Goel Date: Wed, 23 Nov 2016 10:31:08 +0530 Subject: [PATCH 0318/1587] SMACK: Add the rcu synchronization mechanism in ipv6 hooks Add the rcu synchronization mechanism for accessing smk_ipv6_port_list in smack IPv6 hooks. Access to the port list is vulnerable to a race condition issue,it does not apply proper synchronization methods while working on critical section. It is possible that when one thread is reading the list, at the same time another thread is modifying the same port list, which can cause the major problems. To ensure proper synchronization between two threads, rcu mechanism has been applied while accessing and modifying the port list. RCU will also not affect the performance, as there are more accesses than modification where RCU is most effective synchronization mechanism. Signed-off-by: Vishal Goel Signed-off-by: Himanshu Shukla Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 94dc9d406ce3..b76696b84e5c 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -52,6 +52,7 @@ #define SMK_SENDING 2 #ifdef SMACK_IPV6_PORT_LABELING +DEFINE_MUTEX(smack_ipv6_lock); static LIST_HEAD(smk_ipv6_port_list); #endif static struct kmem_cache *smack_inode_cache; @@ -2603,17 +2604,20 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) * on the bound socket. Take the changes to the port * as well. */ - list_for_each_entry(spp, &smk_ipv6_port_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { if (sk != spp->smk_sock) continue; spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; + rcu_read_unlock(); return; } /* * A NULL address is only used for updating existing * bound entries. If there isn't one, it's OK. */ + rcu_read_unlock(); return; } @@ -2629,16 +2633,18 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) * Look for an existing port list entry. * This is an indication that a port is getting reused. */ - list_for_each_entry(spp, &smk_ipv6_port_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { if (spp->smk_port != port) continue; spp->smk_port = port; spp->smk_sock = sk; spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; + rcu_read_unlock(); return; } - + rcu_read_unlock(); /* * A new port entry is required. */ @@ -2651,7 +2657,9 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; - list_add(&spp->list, &smk_ipv6_port_list); + mutex_lock(&smack_ipv6_lock); + list_add_rcu(&spp->list, &smk_ipv6_port_list); + mutex_unlock(&smack_ipv6_lock); return; } @@ -2702,7 +2710,8 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, return 0; port = ntohs(address->sin6_port); - list_for_each_entry(spp, &smk_ipv6_port_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { if (spp->smk_port != port) continue; object = spp->smk_in; @@ -2710,6 +2719,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, ssp->smk_packet = spp->smk_out; break; } + rcu_read_unlock(); return smk_ipv6_check(skp, object, address, act); } From 9d44c97384fdc04585c5d5c985fe88ba7285b5ac Mon Sep 17 00:00:00 2001 From: Vishal Goel Date: Wed, 23 Nov 2016 10:31:59 +0530 Subject: [PATCH 0319/1587] Smack: Fix the issue of permission denied error in ipv6 hook Permission denied error comes when 2 IPv6 servers are running and client tries to connect one of them. Scenario is that both servers are using same IP and port but different protocols(Udp and tcp). They are using different SMACK64IPIN labels.Tcp server is using "test" and udp server is using "test-in". When we try to run tcp client with SMACK64IPOUT label as "test", then connection denied error comes. It should not happen since both tcp server and client labels are same.This happens because there is no check for protocol in smk_ipv6_port_label() function while searching for the earlier port entry. It checks whether there is an existing port entry on the basis of port only. So it updates the earlier port entry in the list. Due to which smack label gets changed for earlier entry in the "smk_ipv6_port_list" list and permission denied error comes. Now a check is added for socket type also.Now if 2 processes use same port but different protocols (tcp or udp), then 2 different port entries will be added in the list. Similarly while checking smack access in smk_ipv6_port_check() function, port entry is searched on the basis of both port and protocol. Signed-off-by: Vishal Goel Signed-off-by: Himanshu Shukla Signed-off-by: Casey Schaufler --- security/smack/smack.h | 1 + security/smack/smack_lsm.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/security/smack/smack.h b/security/smack/smack.h index 77abe2efacae..73480ee07478 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -173,6 +173,7 @@ struct smk_port_label { unsigned short smk_port; /* the port number */ struct smack_known *smk_in; /* inbound label */ struct smack_known *smk_out; /* outgoing label */ + short smk_sock_type; /* Socket type */ }; #endif /* SMACK_IPV6_PORT_LABELING */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index b76696b84e5c..5e4d2bdb38cb 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2635,7 +2635,7 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) */ rcu_read_lock(); list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { - if (spp->smk_port != port) + if (spp->smk_port != port || spp->smk_sock_type != sock->type) continue; spp->smk_port = port; spp->smk_sock = sk; @@ -2656,6 +2656,7 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) spp->smk_sock = sk; spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; + spp->smk_sock_type = sock->type; mutex_lock(&smack_ipv6_lock); list_add_rcu(&spp->list, &smk_ipv6_port_list); @@ -2712,7 +2713,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, port = ntohs(address->sin6_port); rcu_read_lock(); list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { - if (spp->smk_port != port) + if (spp->smk_port != port || spp->smk_sock_type != sk->sk_type) continue; object = spp->smk_in; if (act == SMK_CONNECTING) From 0c96d1f5328e834048480e4696e6867992115c33 Mon Sep 17 00:00:00 2001 From: Vishal Goel Date: Wed, 23 Nov 2016 10:32:54 +0530 Subject: [PATCH 0320/1587] Smack: Fix the issue of wrong SMACK label update in socket bind fail case Fix the issue of wrong SMACK label (SMACK64IPIN) update when a second bind call is made to same IP address & port, but with different SMACK label (SMACK64IPIN) by second instance of server. In this case server returns with "Bind:Address already in use" error but before returning, SMACK label is updated in SMACK port-label mapping list inside smack_socket_bind() hook To fix this issue a new check has been added in smk_ipv6_port_label() function before updating the existing port entry. It checks whether the socket for matching port entry is closed or not. If it is closed then it means port is not bound and it is safe to update the existing port entry else return if port is still getting used. For checking whether socket is closed or not, one more field "smk_can_reuse" has been added in the "smk_port_label" structure. This field will be set to '1' in "smack_sk_free_security()" function which is called to free the socket security blob when the socket is being closed. In this function, port entry is searched in the SMACK port-label mapping list for the closing socket. If entry is found then "smk_can_reuse" field is set to '1'.Initially "smk_can_reuse" field is set to '0' in smk_ipv6_port_label() function after creating a new entry in the list which indicates that socket is in use. Signed-off-by: Vishal Goel Signed-off-by: Himanshu Shukla Signed-off-by: Casey Schaufler --- security/smack/smack.h | 1 + security/smack/smack_lsm.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/security/smack/smack.h b/security/smack/smack.h index 73480ee07478..2fac3b5bf44a 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -174,6 +174,7 @@ struct smk_port_label { struct smack_known *smk_in; /* inbound label */ struct smack_known *smk_out; /* outgoing label */ short smk_sock_type; /* Socket type */ + short smk_can_reuse; }; #endif /* SMACK_IPV6_PORT_LABELING */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 5e4d2bdb38cb..ed6885bccec4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2354,6 +2354,20 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) */ static void smack_sk_free_security(struct sock *sk) { +#ifdef SMACK_IPV6_PORT_LABELING + struct smk_port_label *spp; + + if (sk->sk_family == PF_INET6) { + rcu_read_lock(); + list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { + if (spp->smk_sock != sk) + continue; + spp->smk_can_reuse = 1; + break; + } + rcu_read_unlock(); + } +#endif kfree(sk->sk_security); } @@ -2637,10 +2651,15 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { if (spp->smk_port != port || spp->smk_sock_type != sock->type) continue; + if (spp->smk_can_reuse != 1) { + rcu_read_unlock(); + return; + } spp->smk_port = port; spp->smk_sock = sk; spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; + spp->smk_can_reuse = 0; rcu_read_unlock(); return; } @@ -2657,6 +2676,7 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; spp->smk_sock_type = sock->type; + spp->smk_can_reuse = 0; mutex_lock(&smack_ipv6_lock); list_add_rcu(&spp->list, &smk_ipv6_port_list); From 2e962e2fec5c35b91e3b541e2b8373504bf91e27 Mon Sep 17 00:00:00 2001 From: Vishal Goel Date: Wed, 23 Nov 2016 10:46:57 +0530 Subject: [PATCH 0321/1587] SMACK: Add new lock for adding entry in smack master list "smk_set_access()" function adds a new rule entry in subject label specific list(rule_list) and in global rule list(smack_rule_list) both. Mutex lock (rule_lock) is used to avoid simultaneous updates. But this lock is subject label specific lock. If 2 processes tries to add different rules(i.e with different subject labels) simultaneously, then both the processes can take the "rule_lock" respectively. So it will cause a problem while adding entries in master rule list. Now a new mutex lock(smack_master_list_lock) has been taken to add entry in smack_rule_list to avoid simultaneous updates of different rules. Signed-off-by: Vishal Goel Signed-off-by: Himanshu Shukla Signed-off-by: Casey Schaufler --- security/smack/smackfs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 13743a01b35b..366b8356f75b 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -67,6 +67,7 @@ enum smk_inos { /* * List locks */ +static DEFINE_MUTEX(smack_master_list_lock); static DEFINE_MUTEX(smack_cipso_lock); static DEFINE_MUTEX(smack_ambient_lock); static DEFINE_MUTEX(smk_net4addr_lock); @@ -262,12 +263,16 @@ static int smk_set_access(struct smack_parsed_rule *srp, * it needs to get added for reporting. */ if (global) { + mutex_unlock(rule_lock); smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); if (smlp != NULL) { smlp->smk_rule = sp; + mutex_lock(&smack_master_list_lock); list_add_rcu(&smlp->list, &smack_rule_list); + mutex_unlock(&smack_master_list_lock); } else rc = -ENOMEM; + return rc; } } From d54a197964e7eb636a0c64fb0dbdd67759eb71f2 Mon Sep 17 00:00:00 2001 From: Himanshu Shukla Date: Wed, 23 Nov 2016 11:58:48 +0530 Subject: [PATCH 0322/1587] SMACK: Delete list_head repeated initialization smk_copy_rules() and smk_copy_relabel() are initializing list_head though they have been initialized already in new_task_smack() function. Delete repeated initialization. Signed-off-by: Himanshu Shukla Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index ed6885bccec4..1368f8925343 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -348,8 +348,6 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, struct smack_rule *orp; int rc = 0; - INIT_LIST_HEAD(nhead); - list_for_each_entry_rcu(orp, ohead, list) { nrp = kzalloc(sizeof(struct smack_rule), gfp); if (nrp == NULL) { @@ -376,8 +374,6 @@ static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead, struct smack_known_list_elem *nklep; struct smack_known_list_elem *oklep; - INIT_LIST_HEAD(nhead); - list_for_each_entry(oklep, ohead, list) { nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp); if (nklep == NULL) { From 3d4f673a6988f57e6f6ccd1a3b79eee171545e08 Mon Sep 17 00:00:00 2001 From: Himanshu Shukla Date: Wed, 23 Nov 2016 11:59:19 +0530 Subject: [PATCH 0323/1587] SMACK: Free the i_security blob in inode using RCU There is race condition issue while freeing the i_security blob in SMACK module. There is existing condition where i_security can be freed while inode_permission is called from path lookup on second CPU. There has been observed the page fault with such condition. VFS code and Selinux module takes care of this condition by freeing the inode and i_security field using RCU via call_rcu(). But in SMACK directly the i_secuirty blob is being freed. Use call_rcu() to fix this race condition issue. Signed-off-by: Himanshu Shukla Signed-off-by: Vishal Goel Signed-off-by: Casey Schaufler --- security/smack/smack.h | 1 + security/smack/smack_lsm.c | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/security/smack/smack.h b/security/smack/smack.h index 2fac3b5bf44a..612b810fbbc6 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -114,6 +114,7 @@ struct inode_smack { struct smack_known *smk_mmap; /* label of the mmap domain */ struct mutex smk_lock; /* initialization lock */ int smk_flags; /* smack inode flags */ + struct rcu_head smk_rcu; /* for freeing inode_smack */ }; struct task_smack { diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 1368f8925343..5deda8e0fe96 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1006,15 +1006,39 @@ static int smack_inode_alloc_security(struct inode *inode) } /** - * smack_inode_free_security - free an inode blob + * smack_inode_free_rcu - Free inode_smack blob from cache + * @head: the rcu_head for getting inode_smack pointer + * + * Call back function called from call_rcu() to free + * the i_security blob pointer in inode + */ +static void smack_inode_free_rcu(struct rcu_head *head) +{ + struct inode_smack *issp; + + issp = container_of(head, struct inode_smack, smk_rcu); + kmem_cache_free(smack_inode_cache, issp); +} + +/** + * smack_inode_free_security - free an inode blob using call_rcu() * @inode: the inode with a blob * - * Clears the blob pointer in inode + * Clears the blob pointer in inode using RCU */ static void smack_inode_free_security(struct inode *inode) { - kmem_cache_free(smack_inode_cache, inode->i_security); - inode->i_security = NULL; + struct inode_smack *issp = inode->i_security; + + /* + * The inode may still be referenced in a path walk and + * a call to smack_inode_permission() can be made + * after smack_inode_free_security() is called. + * To avoid race condition free the i_security via RCU + * and leave the current inode->i_security pointer intact. + * The inode will be freed after the RCU grace period too. + */ + call_rcu(&issp->smk_rcu, smack_inode_free_rcu); } /** From 348dc288d4bf4c0272a46a80f97748f36916601b Mon Sep 17 00:00:00 2001 From: Vishal Goel Date: Wed, 23 Nov 2016 10:45:31 +0530 Subject: [PATCH 0324/1587] Smack: Traverse the smack_known_list using list_for_each_entry_rcu macro In smack_from_secattr function,"smack_known_list" is being traversed using list_for_each_entry macro, although it is a rcu protected structure. So it should be traversed using "list_for_each_entry_rcu" macro to fetch the rcu protected entry. Signed-off-by: Vishal Goel Signed-off-by: Himanshu Shukla Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 5deda8e0fe96..4dd458a2b1e8 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3900,7 +3900,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, * ambient value. */ rcu_read_lock(); - list_for_each_entry(skp, &smack_known_list, list) { + list_for_each_entry_rcu(skp, &smack_known_list, list) { if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl) continue; /* From c9d238a18baa92600ba015d6d6c2cde53f55c572 Mon Sep 17 00:00:00 2001 From: Himanshu Shukla Date: Wed, 23 Nov 2016 11:59:45 +0530 Subject: [PATCH 0325/1587] SMACK: Use smk_tskacc() instead of smk_access() for proper logging smack_file_open() is first checking the capability of calling subject, this check will skip the SMACK logging for success case. Use smk_tskacc() for proper logging and SMACK access check. Signed-off-by: Himanshu Shukla Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 4dd458a2b1e8..681583d66c0e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1955,12 +1955,9 @@ static int smack_file_open(struct file *file, const struct cred *cred) struct smk_audit_info ad; int rc; - if (smack_privileged(CAP_MAC_OVERRIDE)) - return 0; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad); + rc = smk_tskacc(tsp, smk_of_inode(inode), MAY_READ, &ad); rc = smk_bu_credfile(cred, file, MAY_READ, rc); return rc; From 805b65a80bed029572c6462cc4be0a260e1482e9 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 9 Dec 2016 14:03:04 +0100 Subject: [PATCH 0326/1587] Smack: fix d_instantiate logic for sockfs and pipefs Since 4b936885a (v2.6.32) all inodes on sockfs and pipefs are disconnected. It caused filesystem specific code in smack_d_instantiate to be skipped, because all inodes on those pseudo filesystems were treated as root inodes. As a result all sockfs inodes had the Smack label set to floor. In most cases access checks for sockets use socket_smack data so the inode label is not important. But there are special cases that were broken. One example would be calling fcntl with F_SETOWN command on a socket fd. Now smack_d_instantiate expects all pipefs and sockfs inodes to be disconnected and has the logic in appropriate place. Signed-off-by: Rafal Krypa Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 681583d66c0e..225c4ad56444 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3486,6 +3486,13 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) case PIPEFS_MAGIC: isp->smk_inode = smk_of_current(); break; + case SOCKFS_MAGIC: + /* + * Socket access is controlled by the socket + * structures associated with the task involved. + */ + isp->smk_inode = &smack_known_star; + break; default: isp->smk_inode = sbsp->smk_root; break; @@ -3502,19 +3509,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ switch (sbp->s_magic) { case SMACK_MAGIC: - case PIPEFS_MAGIC: - case SOCKFS_MAGIC: case CGROUP_SUPER_MAGIC: /* * Casey says that it's a little embarrassing * that the smack file system doesn't do * extended attributes. * - * Casey says pipes are easy (?) - * - * Socket access is controlled by the socket - * structures associated with the task involved. - * * Cgroupfs is special */ final = &smack_known_star; From 83a1e53f392075e291a90746241dce45c6f9429a Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Mon, 12 Dec 2016 17:35:26 +0900 Subject: [PATCH 0327/1587] Smack: ignore private inode for file functions The access to fd from anon_inode is always failed because there is no set xattr operations. So this patch fixes to ignore private inode including anon_inode for file functions. It was only ignored for smack_file_receive() to share dma-buf fd, but dma-buf has other functions like ioctl and mmap. Reference: https://lkml.org/lkml/2015/4/17/16 Signed-off-by: Seung-Woo Kim Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 225c4ad56444..679455350faf 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1647,6 +1647,9 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, struct smk_audit_info ad; struct inode *inode = file_inode(file); + if (unlikely(IS_PRIVATE(inode))) + return 0; + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); @@ -1676,6 +1679,9 @@ static int smack_file_lock(struct file *file, unsigned int cmd) int rc; struct inode *inode = file_inode(file); + if (unlikely(IS_PRIVATE(inode))) + return 0; + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); @@ -1702,6 +1708,9 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, int rc = 0; struct inode *inode = file_inode(file); + if (unlikely(IS_PRIVATE(inode))) + return 0; + switch (cmd) { case F_GETLK: break; @@ -1755,6 +1764,9 @@ static int smack_mmap_file(struct file *file, if (file == NULL) return 0; + if (unlikely(IS_PRIVATE(file_inode(file)))) + return 0; + isp = file_inode(file)->i_security; if (isp->smk_mmap == NULL) return 0; From 26cf9155bf6b7deeaafe8fc8f233fca5e5398c92 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 5 Jan 2017 10:45:09 +0200 Subject: [PATCH 0328/1587] scsi: ufs: ufshcd_query_descriptor_retry should be static Fix the following compilation warning: drivers/scsi/ufs/ufshcd.c:2076:5: warning: no previous prototype for ufshcd_query_descriptor_retry [-Wmissing-prototypes] Also do not export the function, it should not be used out of ufs context. Signed-off-by: Tomas Winkler Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index be6322e38d74..5e95e2b42008 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2410,9 +2410,11 @@ out: * The buf_len parameter will contain, on return, the length parameter * received on the response. */ -int ufshcd_query_descriptor_retry(struct ufs_hba *hba, - enum query_opcode opcode, enum desc_idn idn, u8 index, - u8 selector, u8 *desc_buf, int *buf_len) +static int ufshcd_query_descriptor_retry(struct ufs_hba *hba, + enum query_opcode opcode, + enum desc_idn idn, u8 index, + u8 selector, + u8 *desc_buf, int *buf_len) { int err; int retries; @@ -2426,7 +2428,6 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, return err; } -EXPORT_SYMBOL(ufshcd_query_descriptor_retry); /** * ufshcd_read_desc_param - read the specified descriptor parameter From 8209b6d54e7e2f8b305da831c78629b65d144f91 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 5 Jan 2017 10:45:10 +0200 Subject: [PATCH 0329/1587] scsi: ufs: unexport descritpor reading functions Unexport ufshcd_read_device_desc and ufshcd_read_string_desc there is no really possibility to calling them directly outside of UFS context. Signed-off-by: Tomas Winkler Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 9 ++++----- drivers/scsi/ufs/ufshcd.h | 7 ------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5e95e2b42008..b9b653d332e0 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2545,11 +2545,10 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba, return err; } -int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) +static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) { return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size); } -EXPORT_SYMBOL(ufshcd_read_device_desc); /** * ufshcd_read_string_desc - read string descriptor @@ -2561,8 +2560,9 @@ EXPORT_SYMBOL(ufshcd_read_device_desc); * * Return 0 in case of success, non-zero otherwise */ -int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, - u32 size, bool ascii) +#define ASCII_STD true +static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, + u8 *buf, u32 size, bool ascii) { int err = 0; @@ -2618,7 +2618,6 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, out: return err; } -EXPORT_SYMBOL(ufshcd_read_string_desc); /** * ufshcd_read_unit_desc_param - read the specified unit descriptor parameter diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 0ea49f982cac..7ffcde21975b 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -781,8 +781,6 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba, return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER); } -int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size); - static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info) { return (pwr_info->pwr_rx == FAST_MODE || @@ -791,11 +789,6 @@ static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info) pwr_info->pwr_tx == FASTAUTO_MODE); } -#define ASCII_STD true - -int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, - u32 size, bool ascii); - /* Expose Query-Request API */ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); From d79713f911918e43576338e33396c7f889f5d272 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 5 Jan 2017 10:45:11 +0200 Subject: [PATCH 0330/1587] scsi: ufs: ufshcd_get_max_icc_level fix endianity handling Reading big endian value from a buffer requires explicit cast. Fix sparse warning: drivers/scsi/ufs/ufshcd.c:4825:24: warning: cast to restricted __be16 Signed-off-by: Tomas Winkler Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b9b653d332e0..99731a062f80 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5266,7 +5266,7 @@ static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char *buff) u16 unit; for (i = start_scan; i >= 0; i--) { - data = be16_to_cpu(*((u16 *)(buff + 2*i))); + data = be16_to_cpup((__be16 *)&buff[2 * i]); unit = (data & ATTR_ICC_LVL_UNIT_MASK) >> ATTR_ICC_LVL_UNIT_OFFSET; curr_uA = data & ATTR_ICC_LVL_VALUE_MASK; From 93fdd5ac64bbe80dac6416f048405362d7ef0945 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 5 Jan 2017 10:45:12 +0200 Subject: [PATCH 0331/1587] scsi: ufs: refactor device descriptor reading Pull device descriptor reading out of ufs quirk so it can be used also for other purposes. Revamp the fixup setup: 1. Rename ufs_device_info to ufs_dev_desc as very similar name ufs_dev_info is already in use. 2. Make the handlers static as they are not used out of the ufshdc.c file. [mkp: applied by hand] Signed-off-by: Tomas Winkler Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs.h | 12 +++++++++++ drivers/scsi/ufs/ufs_quirks.h | 28 ++++++------------------ drivers/scsi/ufs/ufshcd.c | 40 +++++++++++++++++------------------ 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 8e6709a3fb6b..318e4a1f76c9 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -523,4 +523,16 @@ struct ufs_dev_info { bool is_lu_power_on_wp; }; +#define MAX_MODEL_LEN 16 +/** + * ufs_dev_desc - ufs device details from the device descriptor + * + * @wmanufacturerid: card details + * @model: card model + */ +struct ufs_dev_desc { + u16 wmanufacturerid; + char model[MAX_MODEL_LEN + 1]; +}; + #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 08b799d4efcc..71f73d1d1ad1 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -21,41 +21,28 @@ #define UFS_ANY_VENDOR 0xFFFF #define UFS_ANY_MODEL "ANY_MODEL" -#define MAX_MODEL_LEN 16 - #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE #define UFS_VENDOR_SKHYNIX 0x1AD -/** - * ufs_device_info - ufs device details - * @wmanufacturerid: card details - * @model: card model - */ -struct ufs_device_info { - u16 wmanufacturerid; - char model[MAX_MODEL_LEN + 1]; -}; - /** * ufs_dev_fix - ufs device quirk info * @card: ufs card details * @quirk: device quirk */ struct ufs_dev_fix { - struct ufs_device_info card; + struct ufs_dev_desc card; unsigned int quirk; }; #define END_FIX { { 0 }, 0 } /* add specific device quirk */ -#define UFS_FIX(_vendor, _model, _quirk) \ - { \ - .card.wmanufacturerid = (_vendor),\ - .card.model = (_model), \ - .quirk = (_quirk), \ - } +#define UFS_FIX(_vendor, _model, _quirk) { \ + .card.wmanufacturerid = (_vendor),\ + .card.model = (_model), \ + .quirk = (_quirk), \ +} /* * If UFS device is having issue in processing LCC (Line Control @@ -144,7 +131,4 @@ struct ufs_dev_fix { */ #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) -struct ufs_hba; -void ufs_advertise_fixup_device(struct ufs_hba *hba); - #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 99731a062f80..dfad19ff166c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5452,8 +5452,8 @@ out: return ret; } -static int ufs_get_device_info(struct ufs_hba *hba, - struct ufs_device_info *card_data) +static int ufs_get_device_desc(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) { int err; u8 model_index; @@ -5472,7 +5472,7 @@ static int ufs_get_device_info(struct ufs_hba *hba, * getting vendor (manufacturerID) and Bank Index in big endian * format */ - card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; @@ -5486,36 +5486,26 @@ static int ufs_get_device_info(struct ufs_hba *hba, } str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; - strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), + strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); /* Null terminate the model string */ - card_data->model[MAX_MODEL_LEN] = '\0'; + dev_desc->model[MAX_MODEL_LEN] = '\0'; out: return err; } -void ufs_advertise_fixup_device(struct ufs_hba *hba) +static void ufs_fixup_device_setup(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) { - int err; struct ufs_dev_fix *f; - struct ufs_device_info card_data; - - card_data.wmanufacturerid = 0; - - err = ufs_get_device_info(hba, &card_data); - if (err) { - dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", - __func__, err); - return; - } for (f = ufs_fixups; f->quirk; f++) { - if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || - (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && - (STR_PRFX_EQUAL(f->card.model, card_data.model) || + if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid || + f->card.wmanufacturerid == UFS_ANY_VENDOR) && + (STR_PRFX_EQUAL(f->card.model, dev_desc->model) || !strcmp(f->card.model, UFS_ANY_MODEL))) hba->dev_quirks |= f->quirk; } @@ -5707,6 +5697,7 @@ static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) */ static int ufshcd_probe_hba(struct ufs_hba *hba) { + struct ufs_dev_desc card = {0}; int ret; ktime_t start = ktime_get(); @@ -5732,7 +5723,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; - ufs_advertise_fixup_device(hba); + ret = ufs_get_device_desc(hba, &card); + if (ret) { + dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", + __func__, ret); + goto out; + } + + ufs_fixup_device_setup(hba, &card); ufshcd_tune_unipro_params(hba); ret = ufshcd_set_vccq_rail_unused(hba, From 47069a81b6312380f163f711ff879bd7a9d0da2a Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 10 Jan 2017 20:16:43 +0800 Subject: [PATCH 0332/1587] scsi: remove useless acpi functions in the header file commit f1bc1e4c44b1 ("ata: acpi: rework the ata acpi bind support") removed scsi_register_acpi_bus_type() and scsi_unregister_acpi_bus_type(), but forgot to remove them in the header file, do it now. Signed-off-by: Hanjun Guo Reviewed-by: John Garry Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- include/scsi/scsi.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 8ec7c30e35af..a1e1930b7a87 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -29,16 +29,6 @@ enum scsi_timeouts { */ #define SCAN_WILD_CARD ~0 -#ifdef CONFIG_ACPI -struct acpi_bus_type; - -extern int -scsi_register_acpi_bus_type(struct acpi_bus_type *bus); - -extern void -scsi_unregister_acpi_bus_type(struct acpi_bus_type *bus); -#endif - /** scsi_status_is_good - check the status return. * * @status: the status passed up from the driver (including host and From 45f4f2eb3da3cbff02c3d77c784c81320c733056 Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:43 -0500 Subject: [PATCH 0333/1587] scsi: megaraid_sas: Add new pci device Ids for SAS3.5 Generic Megaraid Controllers This patch contains new pci device ids for SAS3.5 Generic Megaraid Controllers Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 12 ++++++--- drivers/scsi/megaraid/megaraid_sas_base.c | 14 +++++++++- drivers/scsi/megaraid/megaraid_sas_fusion.c | 30 ++++++++++++++++----- 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index fdd519c1dd57..cb82195a8be1 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -56,6 +56,11 @@ #define PCI_DEVICE_ID_LSI_INTRUDER_24 0x00cf #define PCI_DEVICE_ID_LSI_CUTLASS_52 0x0052 #define PCI_DEVICE_ID_LSI_CUTLASS_53 0x0053 +#define PCI_DEVICE_ID_LSI_VENTURA 0x0014 +#define PCI_DEVICE_ID_LSI_HARPOON 0x0016 +#define PCI_DEVICE_ID_LSI_TOMCAT 0x0017 +#define PCI_DEVICE_ID_LSI_VENTURA_4PORT 0x001B +#define PCI_DEVICE_ID_LSI_CRUSADER_4PORT 0x001C /* * Intel HBA SSDIDs @@ -100,7 +105,7 @@ */ /* - * MFI stands for MegaRAID SAS FW Interface. This is just a moniker for + * MFI stands for MegaRAID SAS FW Interface. This is just a moniker for * protocol between the software and firmware. Commands are issued using * "message frames" */ @@ -1435,7 +1440,7 @@ enum FW_BOOT_CONTEXT { * register set for both 1068 and 1078 controllers * structure extended for 1078 registers */ - + struct megasas_register_set { u32 doorbell; /*0000h*/ u32 fusion_seq_offset; /*0004h*/ @@ -1478,7 +1483,7 @@ struct megasas_register_set { u32 inbound_high_queue_port ; /*00C4h*/ - u32 reserved_5; /*00C8h*/ + u32 inbound_single_queue_port; /*00C8h*/ u32 res_6[11]; /*CCh*/ u32 host_diag; u32 seq_offset; @@ -2142,6 +2147,7 @@ struct megasas_instance { u8 is_rdpq; bool dev_handle; bool fw_sync_cache_support; + bool is_ventura; }; struct MR_LD_VF_MAP { u32 size; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index d5cf15eb8c5e..e00b3dece088 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -155,6 +155,12 @@ static struct pci_device_id megasas_pci_table[] = { /* Intruder 24 port*/ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)}, {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)}, + /* VENTURA */ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_HARPOON)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_TOMCAT)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA_4PORT)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER_4PORT)}, {} }; @@ -5714,6 +5720,12 @@ static int megasas_probe_one(struct pci_dev *pdev, instance->pdev = pdev; switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_VENTURA: + case PCI_DEVICE_ID_LSI_HARPOON: + case PCI_DEVICE_ID_LSI_TOMCAT: + case PCI_DEVICE_ID_LSI_VENTURA_4PORT: + case PCI_DEVICE_ID_LSI_CRUSADER_4PORT: + instance->is_ventura = true; case PCI_DEVICE_ID_LSI_FUSION: case PCI_DEVICE_ID_LSI_PLASMA: case PCI_DEVICE_ID_LSI_INVADER: @@ -5738,7 +5750,7 @@ static int megasas_probe_one(struct pci_dev *pdev, if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) fusion->adapter_type = THUNDERBOLT_SERIES; - else + else if (!instance->is_ventura) fusion->adapter_type = INVADER_SERIES; } break; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 24778ba4b6e8..8d7a39782512 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -189,15 +189,29 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, */ static void megasas_fire_cmd_fusion(struct megasas_instance *instance, - union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, bool is_32bit) { + struct megasas_register_set __iomem *regs = instance->reg_set; + unsigned long flags; + + if (is_32bit) + writel(le32_to_cpu(req_desc->u.low), + &(regs)->inbound_single_queue_port); + else if (instance->is_ventura) { + spin_lock_irqsave(&instance->hba_lock, flags); + writel(le32_to_cpu(req_desc->u.low), + &(regs)->inbound_low_queue_port); + writel(le32_to_cpu(req_desc->u.high), + &(regs)->inbound_high_queue_port); + mmiowb(); + spin_unlock_irqrestore(&instance->hba_lock, flags); + } else { #if defined(writeq) && defined(CONFIG_64BIT) u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | le32_to_cpu(req_desc->u.low)); writeq(req_data, &instance->reg_set->inbound_low_queue_port); #else - unsigned long flags; spin_lock_irqsave(&instance->hba_lock, flags); writel(le32_to_cpu(req_desc->u.low), @@ -207,6 +221,7 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, mmiowb(); spin_unlock_irqrestore(&instance->hba_lock, flags); #endif + } } /** @@ -850,7 +865,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) break; } - megasas_fire_cmd_fusion(instance, &req_desc); + megasas_fire_cmd_fusion(instance, &req_desc, false); wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS); @@ -2224,7 +2239,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, */ atomic_inc(&instance->fw_outstanding); - megasas_fire_cmd_fusion(instance, req_desc); + megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura); return 0; } @@ -2595,7 +2610,7 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance, return DCMD_NOT_FIRED; } - megasas_fire_cmd_fusion(instance, req_desc); + megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura); return DCMD_SUCCESS; } @@ -2888,7 +2903,8 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO))) && !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE); if (refire_cmd) - megasas_fire_cmd_fusion(instance, req_desc); + megasas_fire_cmd_fusion(instance, req_desc, + instance->is_ventura); else megasas_return_cmd(instance, cmd_mfi); } @@ -3067,7 +3083,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, mr_request->tmReqFlags.isTMForLD = 1; init_completion(&cmd_fusion->done); - megasas_fire_cmd_fusion(instance, req_desc); + megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura); timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ); From 2493c67e518c772a573c3b1ad02e7ced5b53f6ca Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:44 -0500 Subject: [PATCH 0334/1587] scsi: megaraid_sas: 128 MSIX Support SAS3.5 Generic Megaraid based Controllers will have the support for 128 MSI-X vectors, resulting in the need to support 128 reply queues Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 1 + drivers/scsi/megaraid/megaraid_sas_base.c | 25 +++++++++++++++------ drivers/scsi/megaraid/megaraid_sas_fusion.c | 4 ++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index cb82195a8be1..36aac88571fc 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2148,6 +2148,7 @@ struct megasas_instance { bool dev_handle; bool fw_sync_cache_support; bool is_ventura; + bool msix_combined; }; struct MR_LD_VF_MAP { u32 size; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index e00b3dece088..6801a449d236 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5072,13 +5072,7 @@ static int megasas_init_fw(struct megasas_instance *instance) goto fail_ready_state; } - /* - * MSI-X host index 0 is common for all adapter. - * It is used for all MPT based Adapters. - */ - instance->reply_post_host_index_addr[0] = - (u32 __iomem *)((u8 __iomem *)instance->reg_set + - MPI2_REPLY_POST_HOST_INDEX_OFFSET); + /* Check if MSI-X is supported while in ready state */ msix_enable = (instance->instancet->read_fw_status_reg(reg_set) & @@ -5098,6 +5092,9 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->msix_vectors = ((scratch_pad_2 & MR_MAX_REPLY_QUEUES_EXT_OFFSET) >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; + if (instance->msix_vectors > 16) + instance->msix_combined = true; + if (rdpq_enable) instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; @@ -5131,6 +5128,20 @@ static int megasas_init_fw(struct megasas_instance *instance) else instance->msix_vectors = 0; } + /* + * MSI-X host index 0 is common for all adapter. + * It is used for all MPT based Adapters. + */ + if (instance->msix_combined) { + instance->reply_post_host_index_addr[0] = + (u32 *)((u8 *)instance->reg_set + + MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET); + } else { + instance->reply_post_host_index_addr[0] = + (u32 *)((u8 *)instance->reg_set + + MPI2_REPLY_POST_HOST_INDEX_OFFSET); + } + i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY); if (i < 0) goto fail_setup_irqs; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 8d7a39782512..413e20308871 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2391,7 +2391,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) * pending to be completed */ if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) { - if (fusion->adapter_type == INVADER_SERIES) + if (instance->msix_combined) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[MSIxIndex/8]); @@ -2407,7 +2407,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) return IRQ_NONE; wmb(); - if (fusion->adapter_type == INVADER_SERIES) + if (instance->msix_combined) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[MSIxIndex/8]); From 45d446038c7b93c40b2fe5ba0e95380f19e0493e Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:45 -0500 Subject: [PATCH 0335/1587] scsi: megaraid_sas: EEDP Escape Mode Support for SAS3.5 Generic Megaraid Controllers An UNMAP command on a PI formatted device will leave the Logical Block Application Tag and Logical Block Reference Tag as all F's (for those LBAs that are unmapped). To avoid IO errors if those LBAs are subsequently read before they are written with valid tag fields, the MPI SCSI IO requests need to set the EEDPFlags element EEDP Escape Mode field, Bits [7:6] appropriately. A value of 2 should be set to disable all PI checks if the Logical Block Application Tag is 0xFFFF for PI types 1 and 2. A value of 3 should be set to disable all PI checks if the Logical Block Application Tag is 0xFFFF and the Logical Block Reference Tag is 0xFFFFFFFF for PI type 3. Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 1 + drivers/scsi/megaraid/megaraid_sas_fusion.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 413e20308871..fe69c4a0eb22 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1589,6 +1589,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP | MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG | + MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE | MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); } else { io_request->EEDPFlags = cpu_to_le16( diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index e3bee04c1eb1..9d22adea5861 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -175,6 +175,8 @@ enum REGION_TYPE { #define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) +/* EEDP escape mode */ +#define MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE (0x0040) #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ #define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03) From fdd84e2514b0157219720cf8f3f55757938a39cd Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:46 -0500 Subject: [PATCH 0336/1587] scsi: megaraid_sas: SAS3.5 Generic Megaraid Controllers Stream Detection and IO Coalescing Detect sequential Write IOs and pass the hint that it is part of sequential stream to help HBA Firmware do the Full Stripe Writes. For read IOs on certain RAID volumes like Read Ahead volumes,this will help driver to send it to Firmware even if the IOs can potentially be sent to hardware directly (called fast path) bypassing firmware. Design: 8 streams are maintained per RAID volume as per the combined firmware/driver design. When there is no stream detected the LRU stream is used for next potential stream and LRU/MRU map is updated to make this as MRU stream. Every time a stream is detected the MRU map is updated to make the current stream as MRU stream. Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 1 + drivers/scsi/megaraid/megaraid_sas_base.c | 43 ++++- drivers/scsi/megaraid/megaraid_sas_fp.c | 2 + drivers/scsi/megaraid/megaraid_sas_fusion.c | 165 ++++++++++++++++---- drivers/scsi/megaraid/megaraid_sas_fusion.h | 117 +++++++++++++- 5 files changed, 297 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 36aac88571fc..3d86bc65222d 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2070,6 +2070,7 @@ struct megasas_instance { /* used to sync fire the cmd to fw */ spinlock_t hba_lock; /* used to synch producer, consumer ptrs in dpc */ + spinlock_t stream_lock; spinlock_t completion_lock; struct dma_pool *frame_dma_pool; struct dma_pool *sense_dma_pool; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 6801a449d236..b2b1d29ec942 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5001,7 +5001,7 @@ static int megasas_init_fw(struct megasas_instance *instance) struct megasas_register_set __iomem *reg_set; struct megasas_ctrl_info *ctrl_info = NULL; unsigned long bar_list; - int i, loop, fw_msix_count = 0; + int i, j, loop, fw_msix_count = 0; struct IOV_111 *iovPtr; struct fusion_context *fusion; @@ -5194,6 +5194,36 @@ static int megasas_init_fw(struct megasas_instance *instance) } memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); + + /* stream detection initialization */ + if (instance->is_ventura) { + fusion->stream_detect_by_ld = + kzalloc(sizeof(struct LD_STREAM_DETECT *) + * MAX_LOGICAL_DRIVES_EXT, + GFP_KERNEL); + if (!fusion->stream_detect_by_ld) { + dev_err(&instance->pdev->dev, + "unable to allocate stream detection for pool of LDs\n"); + goto fail_get_ld_pd_list; + } + for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) { + fusion->stream_detect_by_ld[i] = + kmalloc(sizeof(struct LD_STREAM_DETECT), + GFP_KERNEL); + if (!fusion->stream_detect_by_ld[i]) { + dev_err(&instance->pdev->dev, + "unable to allocate stream detect by LD\n "); + for (j = 0; j < i; ++j) + kfree(fusion->stream_detect_by_ld[j]); + kfree(fusion->stream_detect_by_ld); + fusion->stream_detect_by_ld = NULL; + goto fail_get_ld_pd_list; + } + fusion->stream_detect_by_ld[i]->mru_bit_map + = MR_STREAM_BITMAP; + } + } + if (megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) megasas_get_ld_list(instance); @@ -5313,6 +5343,8 @@ static int megasas_init_fw(struct megasas_instance *instance) return 0; +fail_get_ld_pd_list: + instance->instancet->disable_intr(instance); fail_get_pd_list: instance->instancet->disable_intr(instance); fail_init_adapter: @@ -5846,6 +5878,7 @@ static int megasas_probe_one(struct pci_dev *pdev, spin_lock_init(&instance->mfi_pool_lock); spin_lock_init(&instance->hba_lock); + spin_lock_init(&instance->stream_lock); spin_lock_init(&instance->completion_lock); mutex_init(&instance->reset_mutex); @@ -6353,6 +6386,14 @@ skip_firing_dcmds: if (instance->msix_vectors) pci_free_irq_vectors(instance->pdev); + if (instance->is_ventura) { + for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) + kfree(fusion->stream_detect_by_ld[i]); + kfree(fusion->stream_detect_by_ld); + fusion->stream_detect_by_ld = NULL; + } + + if (instance->ctrl_context) { megasas_release_fusion(instance); pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index f237d0003df3..a4e213be69d2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -935,6 +935,8 @@ MR_BuildRaidContext(struct megasas_instance *instance, ld = MR_TargetIdToLdGet(ldTgtId, map); raid = MR_LdRaidGet(ld, map); + /*check read ahead bit*/ + io_info->ra_capable = raid->capability.ra_capable; /* * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index fe69c4a0eb22..974fb3c37ad4 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1703,6 +1703,90 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, } } +/** + * megasas_stream_detect - stream detection on read and and write IOs + * @instance: Adapter soft state + * @cmd: Command to be prepared + * @io_info: IO Request info + * + */ + +/** stream detection on read and and write IOs */ +static void megasas_stream_detect(struct megasas_instance *instance, + struct megasas_cmd_fusion *cmd, + struct IO_REQUEST_INFO *io_info) +{ + struct fusion_context *fusion = instance->ctrl_context; + u32 device_id = io_info->ldTgtId; + struct LD_STREAM_DETECT *current_ld_sd + = fusion->stream_detect_by_ld[device_id]; + u32 *track_stream = ¤t_ld_sd->mru_bit_map, stream_num; + u32 shifted_values, unshifted_values; + u32 index_value_mask, shifted_values_mask; + int i; + bool is_read_ahead = false; + struct STREAM_DETECT *current_sd; + /* find possible stream */ + for (i = 0; i < MAX_STREAMS_TRACKED; ++i) { + stream_num = + (*track_stream >> (i * BITS_PER_INDEX_STREAM)) & + STREAM_MASK; + current_sd = ¤t_ld_sd->stream_track[stream_num]; + /* if we found a stream, update the raid + * context and also update the mruBitMap + */ + /* boundary condition */ + if ((current_sd->next_seq_lba) && + (io_info->ldStartBlock >= current_sd->next_seq_lba) && + (io_info->ldStartBlock <= (current_sd->next_seq_lba+32)) && + (current_sd->is_read == io_info->isRead)) { + + if ((io_info->ldStartBlock != current_sd->next_seq_lba) + && ((!io_info->isRead) || (!is_read_ahead))) + /* + * Once the API availible we need to change this. + * At this point we are not allowing any gap + */ + continue; + + cmd->io_request->RaidContext.raid_context_g35.stream_detected = true; + current_sd->next_seq_lba = + io_info->ldStartBlock + io_info->numBlocks; + /* + * update the mruBitMap LRU + */ + shifted_values_mask = + (1 << i * BITS_PER_INDEX_STREAM) - 1; + shifted_values = ((*track_stream & shifted_values_mask) + << BITS_PER_INDEX_STREAM); + index_value_mask = + STREAM_MASK << i * BITS_PER_INDEX_STREAM; + unshifted_values = + *track_stream & ~(shifted_values_mask | + index_value_mask); + *track_stream = + unshifted_values | shifted_values | stream_num; + return; + + } + + } + /* + * if we did not find any stream, create a new one + * from the least recently used + */ + stream_num = + (*track_stream >> ((MAX_STREAMS_TRACKED - 1) * BITS_PER_INDEX_STREAM)) & + STREAM_MASK; + current_sd = ¤t_ld_sd->stream_track[stream_num]; + current_sd->is_read = io_info->isRead; + current_sd->next_seq_lba = io_info->ldStartBlock + io_info->numBlocks; + *track_stream = + (((*track_stream & ZERO_LAST_STREAM) << 4) | stream_num); + return; + +} + /** * megasas_build_ldio_fusion - Prepares IOs to devices * @instance: Adapter soft state @@ -1725,15 +1809,17 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, struct fusion_context *fusion; struct MR_DRV_RAID_MAP_ALL *local_map_ptr; u8 *raidLUN; + unsigned long spinlock_flags; device_id = MEGASAS_DEV_INDEX(scp); fusion = instance->ctrl_context; io_request = cmd->io_request; - io_request->RaidContext.VirtualDiskTgtId = cpu_to_le16(device_id); - io_request->RaidContext.status = 0; - io_request->RaidContext.exStatus = 0; + io_request->RaidContext.raid_context.VirtualDiskTgtId = + cpu_to_le16(device_id); + io_request->RaidContext.raid_context.status = 0; + io_request->RaidContext.raid_context.exStatus = 0; req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc; @@ -1804,11 +1890,11 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >= instance->fw_supported_vd_count) || (!fusion->fast_path_io)) { - io_request->RaidContext.regLockFlags = 0; + io_request->RaidContext.raid_context.regLockFlags = 0; fp_possible = 0; } else { if (MR_BuildRaidContext(instance, &io_info, - &io_request->RaidContext, + &io_request->RaidContext.raid_context, local_map_ptr, &raidLUN)) fp_possible = io_info.fpOkForIo; } @@ -1819,6 +1905,18 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ? raw_smp_processor_id() % instance->msix_vectors : 0; + if (instance->is_ventura) { + spin_lock_irqsave(&instance->stream_lock, spinlock_flags); + megasas_stream_detect(instance, cmd, &io_info); + spin_unlock_irqrestore(&instance->stream_lock, spinlock_flags); + /* In ventura if stream detected for a read and it is read ahead + * capable make this IO as LDIO + */ + if (io_request->RaidContext.raid_context_g35.stream_detected && + io_info.isRead && io_info.ra_capable) + fp_possible = false; + } + if (fp_possible) { megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp, local_map_ptr, start_lba_lo); @@ -1827,15 +1925,16 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (fusion->adapter_type == INVADER_SERIES) { - if (io_request->RaidContext.regLockFlags == + if (io_request->RaidContext.raid_context.regLockFlags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - io_request->RaidContext.Type = MPI2_TYPE_CUDA; - io_request->RaidContext.nseg = 0x1; + io_request->RaidContext.raid_context.Type + = MPI2_TYPE_CUDA; + io_request->RaidContext.raid_context.nseg = 0x1; io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); - io_request->RaidContext.regLockFlags |= + io_request->RaidContext.raid_context.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | MR_RL_FLAGS_SEQ_NUM_ENABLE); } @@ -1862,22 +1961,24 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, /* populate the LUN field */ memcpy(io_request->LUN, raidLUN, 8); } else { - io_request->RaidContext.timeoutValue = + io_request->RaidContext.raid_context.timeoutValue = cpu_to_le16(local_map_ptr->raidMap.fpPdIoTimeoutSec); cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (fusion->adapter_type == INVADER_SERIES) { if (io_info.do_fp_rlbypass || - (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED)) + (io_request->RaidContext.raid_context.regLockFlags + == REGION_TYPE_UNUSED)) cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - io_request->RaidContext.Type = MPI2_TYPE_CUDA; - io_request->RaidContext.regLockFlags |= + io_request->RaidContext.raid_context.Type + = MPI2_TYPE_CUDA; + io_request->RaidContext.raid_context.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | MR_RL_FLAGS_SEQ_NUM_ENABLE); - io_request->RaidContext.nseg = 0x1; + io_request->RaidContext.raid_context.nseg = 0x1; } io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; io_request->DevHandle = cpu_to_le16(device_id); @@ -1913,7 +2014,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance, local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); /* get RAID_Context pointer */ - pRAID_Context = &io_request->RaidContext; + pRAID_Context = &io_request->RaidContext.raid_context; /* Check with FW team */ pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); pRAID_Context->regLockRowLBA = 0; @@ -2000,7 +2101,7 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, io_request = cmd->io_request; /* get RAID_Context pointer */ - pRAID_Context = &io_request->RaidContext; + pRAID_Context = &io_request->RaidContext.raid_context; pRAID_Context->regLockFlags = 0; pRAID_Context->regLockRowLBA = 0; pRAID_Context->regLockLength = 0; @@ -2094,9 +2195,9 @@ megasas_build_io_fusion(struct megasas_instance *instance, io_request->Control = 0; io_request->EEDPBlockSize = 0; io_request->ChainOffset = 0; - io_request->RaidContext.RAIDFlags = 0; - io_request->RaidContext.Type = 0; - io_request->RaidContext.nseg = 0; + io_request->RaidContext.raid_context.RAIDFlags = 0; + io_request->RaidContext.raid_context.Type = 0; + io_request->RaidContext.raid_context.nseg = 0; memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len); /* @@ -2143,8 +2244,8 @@ megasas_build_io_fusion(struct megasas_instance *instance, /* numSGE store lower 8 bit of sge_count. * numSGEExt store higher 8 bit of sge_count */ - io_request->RaidContext.numSGE = sge_count; - io_request->RaidContext.numSGEExt = (u8)(sge_count >> 8); + io_request->RaidContext.raid_context.numSGE = sge_count; + io_request->RaidContext.raid_context.numSGEExt = (u8)(sge_count >> 8); io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING); @@ -2303,8 +2404,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) cmd_fusion->scmd->SCp.ptr = NULL; scmd_local = cmd_fusion->scmd; - status = scsi_io_req->RaidContext.status; - extStatus = scsi_io_req->RaidContext.exStatus; + status = scsi_io_req->RaidContext.raid_context.status; + extStatus = scsi_io_req->RaidContext.raid_context.exStatus; switch (scsi_io_req->Function) { case MPI2_FUNCTION_SCSI_TASK_MGMT: @@ -2337,8 +2438,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */ /* Map the FW Cmd Status */ map_cmd_status(cmd_fusion, status, extStatus); - scsi_io_req->RaidContext.status = 0; - scsi_io_req->RaidContext.exStatus = 0; + scsi_io_req->RaidContext.raid_context.status = 0; + scsi_io_req->RaidContext.raid_context.exStatus = 0; if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) atomic_dec(&instance->ldio_outstanding); megasas_return_cmd_fusion(instance, cmd_fusion); @@ -2905,7 +3006,7 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) && !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE); if (refire_cmd) megasas_fire_cmd_fusion(instance, req_desc, - instance->is_ventura); + instance->is_ventura); else megasas_return_cmd(instance, cmd_mfi); } @@ -3394,7 +3495,7 @@ int megasas_check_mpio_paths(struct megasas_instance *instance, /* Core fusion reset function */ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) { - int retval = SUCCESS, i, convert = 0; + int retval = SUCCESS, i, j, convert = 0; struct megasas_instance *instance; struct megasas_cmd_fusion *cmd_fusion; struct fusion_context *fusion; @@ -3559,6 +3660,16 @@ transition_to_ready: shost_for_each_device(sdev, shost) megasas_update_sdev_properties(sdev); + /* reset stream detection array */ + if (instance->is_ventura) { + for (j = 0; j < MAX_LOGICAL_DRIVES_EXT; ++j) { + memset(fusion->stream_detect_by_ld[j], + 0, sizeof(struct LD_STREAM_DETECT)); + fusion->stream_detect_by_ld[j]->mru_bit_map + = MR_STREAM_BITMAP; + } + } + clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 9d22adea5861..3909a26a5d31 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -133,12 +133,95 @@ struct RAID_CONTEXT { u8 resvd2; }; +/* + * Raid Context structure which describes ventura MegaRAID specific + * IO Paramenters ,This resides at offset 0x60 where the SGL normally + * starts in MPT IO Frames + */ +struct RAID_CONTEXT_G35 { +#if defined(__BIG_ENDIAN_BITFIELD) + u16 resvd0:8; + u16 nseg:4; + u16 type:4; +#else + u16 type:4; /* 0x00 */ + u16 nseg:4; /* 0x00 */ + u16 resvd0:8; +#endif + u16 timeout_value; /* 0x02 -0x03 */ + union { + struct { +#if defined(__BIG_ENDIAN_BITFIELD) + u16 set_divert:4; + u16 cpu_sel:4; + u16 log:1; + u16 rw:1; + u16 sbs:1; + u16 sqn:1; + u16 fwn:1; + u16 c2f:1; + u16 sld:1; + u16 reserved:1; +#else + u16 reserved:1; + u16 sld:1; + u16 c2f:1; + u16 fwn:1; + u16 sqn:1; + u16 sbs:1; + u16 rw:1; + u16 log:1; + u16 cpu_sel:4; + u16 set_divert:4; +#endif + } bits; + u16 s; + } routing_flags; /* 0x04 -0x05 routing flags */ + u16 virtual_disk_tgt_id; /* 0x06 -0x07 */ + u64 reg_lock_row_lba; /* 0x08 - 0x0F */ + u32 reg_lock_length; /* 0x10 - 0x13 */ + union { + u16 next_lmid; /* 0x14 - 0x15 */ + u16 peer_smid; /* used for the raid 1/10 fp writes */ + } smid; + u8 ex_status; /* 0x16 : OUT */ + u8 status; /* 0x17 status */ + u8 RAIDFlags; /* 0x18 resvd[7:6], ioSubType[5:4], + * resvd[3:1], preferredCpu[0] + */ + u8 span_arm; /* 0x1C span[7:5], arm[4:0] */ + u16 config_seq_num; /* 0x1A -0x1B */ +#if defined(__BIG_ENDIAN_BITFIELD) /* 0x1C - 0x1D */ + u16 stream_detected:1; + u16 reserved:3; + u16 num_sge:12; +#else + u16 num_sge:12; + u16 reserved:3; + u16 stream_detected:1; +#endif + u8 resvd2[2]; /* 0x1E-0x1F */ +}; + +union RAID_CONTEXT_UNION { + struct RAID_CONTEXT raid_context; + struct RAID_CONTEXT_G35 raid_context_g35; +}; + #define RAID_CTX_SPANARM_ARM_SHIFT (0) #define RAID_CTX_SPANARM_ARM_MASK (0x1f) #define RAID_CTX_SPANARM_SPAN_SHIFT (5) #define RAID_CTX_SPANARM_SPAN_MASK (0xE0) +/* number of bits per index in U32 TrackStream */ +#define BITS_PER_INDEX_STREAM 4 +#define INVALID_STREAM_NUM 16 +#define MR_STREAM_BITMAP 0x76543210 +#define STREAM_MASK ((1 << BITS_PER_INDEX_STREAM) - 1) +#define ZERO_LAST_STREAM 0x0fffffff +#define MAX_STREAMS_TRACKED 8 + /* * define region lock types */ @@ -409,7 +492,7 @@ struct MPI2_RAID_SCSI_IO_REQUEST { u8 LUN[8]; /* 0x34 */ __le32 Control; /* 0x3C */ union MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ - struct RAID_CONTEXT RaidContext; /* 0x60 */ + union RAID_CONTEXT_UNION RaidContext; /* 0x60 */ union MPI2_SGE_IO_UNION SGL; /* 0x80 */ }; @@ -656,11 +739,13 @@ struct MR_LD_RAID { u32 encryptionType:8; u32 pdPiMode:4; u32 ldPiMode:4; - u32 reserved5:3; + u32 reserved5:2; + u32 ra_capable:1; u32 fpCapable:1; #else u32 fpCapable:1; - u32 reserved5:3; + u32 ra_capable:1; + u32 reserved5:2; u32 ldPiMode:4; u32 pdPiMode:4; u32 encryptionType:8; @@ -745,6 +830,7 @@ struct IO_REQUEST_INFO { u64 start_row; u8 span_arm; /* span[7:5], arm[4:0] */ u8 pd_after_lb; + bool ra_capable; }; struct MR_LD_TARGET_SYNC { @@ -930,6 +1016,30 @@ struct MR_PD_CFG_SEQ_NUM_SYNC { struct MR_PD_CFG_SEQ seq[1]; } __packed; +/* stream detection */ +struct STREAM_DETECT { + u64 next_seq_lba; /* next LBA to match sequential access */ + struct megasas_cmd_fusion *first_cmd_fusion; /* first cmd in group */ + struct megasas_cmd_fusion *last_cmd_fusion; /* last cmd in group */ + u32 count_cmds_in_stream; /* count of host commands in this stream */ + u16 num_sges_in_group; /* total number of SGEs in grouped IOs */ + u8 is_read; /* SCSI OpCode for this stream */ + u8 group_depth; /* total number of host commands in group */ + /* TRUE if cannot add any more commands to this group */ + bool group_flush; + u8 reserved[7]; /* pad to 64-bit alignment */ +}; + +struct LD_STREAM_DETECT { + bool write_back; /* TRUE if WB, FALSE if WT */ + bool fp_write_enabled; + bool members_ssds; + bool fp_cache_bypass_capable; + u32 mru_bit_map; /* bitmap used to track MRU and LRU stream indicies */ + /* this is the array of stream detect structures (one per stream) */ + struct STREAM_DETECT stream_track[MAX_STREAMS_TRACKED]; +}; + struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { u64 RDPQBaseAddress; u32 Reserved1; @@ -983,6 +1093,7 @@ struct fusion_context { struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT]; LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT]; u8 adapter_type; + struct LD_STREAM_DETECT **stream_detect_by_ld; }; union desc_value { From 69c337c0f8d74d71e085efa8869be9fc51e5962b Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:47 -0500 Subject: [PATCH 0337/1587] scsi: megaraid_sas: SAS3.5 Generic Megaraid Controllers Fast Path for RAID 1/10 Writes To improve RAID 1/10 Write performance, OS drivers need to issue the required Write IOs as Fast Path IOs (after the appropriate checks allowing Fast Path to be used) to the appropriate physical drives (translated from the OS logical IO) and wait for all Write IOs to complete. Design: A write IO on RAID volume will be examined if it can be sent in Fast Path based on IO size and starting LBA and ending LBA falling on to a Physical Drive boundary. If the underlying RAID volume is a RAID 1/10, driver issues two fast path write IOs one for each corresponding physical drive after computing the corresponding start LBA for each physical drive. Both write IOs will have the same payload and are posted to HW such that replies land in the same reply queue. If there are no resources available for sending two IOs, driver will send the original IO from SCSI layer to RAID volume through the Firmware. Based on PCI bandwidth and write payload, every second this feature is enabled/disabled. When both IOs are completed by HW, the resources will be released and SCSI IO completion handler will be called. Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 1 + drivers/scsi/megaraid/megaraid_sas_fp.c | 31 +- drivers/scsi/megaraid/megaraid_sas_fusion.c | 335 +++++++++++++++++--- drivers/scsi/megaraid/megaraid_sas_fusion.h | 15 +- 4 files changed, 329 insertions(+), 53 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 3d86bc65222d..a96889c34db0 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2056,6 +2056,7 @@ struct megasas_instance { u16 max_num_sge; u16 max_fw_cmds; + u16 max_mpt_cmds; u16 max_mfi_cmds; u16 max_scsi_cmds; u16 ldio_threshold; diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index a4e213be69d2..eb9ff444c099 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -737,7 +737,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, struct MR_DRV_RAID_MAP_ALL *map) { struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); - u32 pd, arRef; + u32 pd, arRef, r1_alt_pd; u8 physArm, span; u64 row; u8 retval = TRUE; @@ -772,9 +772,16 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, arRef = MR_LdSpanArrayGet(ld, span, map); pd = MR_ArPdGet(arRef, physArm, map); - if (pd != MR_PD_INVALID) + if (pd != MR_PD_INVALID) { *pDevHandle = MR_PdDevHandleGet(pd, map); - else { + /* get second pd also for raid 1/10 fast path writes*/ + if (raid->level == 1) { + r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map); + if (r1_alt_pd != MR_PD_INVALID) + io_info->r1_alt_dev_handle = + MR_PdDevHandleGet(r1_alt_pd, map); + } + } else { *pDevHandle = cpu_to_le16(MR_PD_INVALID); if ((raid->level >= 5) && ((fusion->adapter_type == THUNDERBOLT_SERIES) || @@ -819,7 +826,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, struct MR_DRV_RAID_MAP_ALL *map) { struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); - u32 pd, arRef; + u32 pd, arRef, r1_alt_pd; u8 physArm, span; u64 row; u8 retval = TRUE; @@ -867,10 +874,17 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, arRef = MR_LdSpanArrayGet(ld, span, map); pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */ - if (pd != MR_PD_INVALID) + if (pd != MR_PD_INVALID) { /* Get dev handle from Pd. */ *pDevHandle = MR_PdDevHandleGet(pd, map); - else { + /* get second pd also for raid 1/10 fast path writes*/ + if (raid->level == 1) { + r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map); + if (r1_alt_pd != MR_PD_INVALID) + io_info->r1_alt_dev_handle = + MR_PdDevHandleGet(r1_alt_pd, map); + } + } else { /* set dev handle as invalid. */ *pDevHandle = cpu_to_le16(MR_PD_INVALID); if ((raid->level >= 5) && @@ -1126,6 +1140,11 @@ MR_BuildRaidContext(struct megasas_instance *instance, /* If IO on an invalid Pd, then FP is not possible.*/ if (io_info->devHandle == cpu_to_le16(MR_PD_INVALID)) io_info->fpOkForIo = FALSE; + /* set raid 1/10 fast path write capable bit in io_info */ + if (io_info->fpOkForIo && + (io_info->r1_alt_dev_handle != MR_PD_INVALID) && + (raid->level == 1) && !isRead) + io_info->is_raid_1_fp_write = 1; return retval; } else if (isRead) { uint stripIdx; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 974fb3c37ad4..792f26918ed6 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -270,7 +270,8 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c instance->ldio_threshold = ldio_threshold; if (!instance->is_rdpq) - instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024); + instance->max_fw_cmds = + min_t(u16, instance->max_fw_cmds, 1024); if (reset_devices) instance->max_fw_cmds = min(instance->max_fw_cmds, @@ -286,7 +287,14 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c (MEGASAS_FUSION_INTERNAL_CMDS + MEGASAS_FUSION_IOCTL_CMDS); instance->cur_can_queue = instance->max_scsi_cmds; + instance->host->can_queue = instance->cur_can_queue; } + + if (instance->is_ventura) + instance->max_mpt_cmds = + instance->max_fw_cmds * RAID_1_10_RMW_CMDS; + else + instance->max_mpt_cmds = instance->max_fw_cmds; } /** * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool @@ -300,7 +308,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance) struct megasas_cmd_fusion *cmd; /* SG, Sense */ - for (i = 0; i < instance->max_fw_cmds; i++) { + for (i = 0; i < instance->max_mpt_cmds; i++) { cmd = fusion->cmd_list[i]; if (cmd) { if (cmd->sg_frame) @@ -344,7 +352,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance) /* cmd_list */ - for (i = 0; i < instance->max_fw_cmds; i++) + for (i = 0; i < instance->max_mpt_cmds; i++) kfree(fusion->cmd_list[i]); kfree(fusion->cmd_list); @@ -396,33 +404,49 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) return -ENOMEM; } } + + /* create sense buffer for the raid 1/10 fp */ + for (i = max_cmd; i < instance->max_mpt_cmds; i++) { + cmd = fusion->cmd_list[i]; + cmd->sense = pci_pool_alloc(fusion->sense_dma_pool, + GFP_KERNEL, &cmd->sense_phys_addr); + if (!cmd->sense) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + } + return 0; } int megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) { - u32 max_cmd, i; + u32 max_mpt_cmd, i; struct fusion_context *fusion; fusion = instance->ctrl_context; - max_cmd = instance->max_fw_cmds; + max_mpt_cmd = instance->max_mpt_cmds; /* * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. * Allocate the dynamic array first and then allocate individual * commands. */ - fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd, - GFP_KERNEL); + fusion->cmd_list = + kzalloc(sizeof(struct megasas_cmd_fusion *) * max_mpt_cmd, + GFP_KERNEL); if (!fusion->cmd_list) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); return -ENOMEM; } - for (i = 0; i < max_cmd; i++) { + + + for (i = 0; i < max_mpt_cmd; i++) { fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion), GFP_KERNEL); if (!fusion->cmd_list[i]) { @@ -657,13 +681,14 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) */ /* SMID 0 is reserved. Set SMID/index from 1 */ - for (i = 0; i < instance->max_fw_cmds; i++) { + for (i = 0; i < instance->max_mpt_cmds; i++) { cmd = fusion->cmd_list[i]; offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); cmd->index = i + 1; cmd->scmd = NULL; - cmd->sync_cmd_idx = (i >= instance->max_scsi_cmds) ? + cmd->sync_cmd_idx = + (i >= instance->max_scsi_cmds && i < instance->max_fw_cmds) ? (i - instance->max_scsi_cmds) : (u32)ULONG_MAX; /* Set to Invalid */ cmd->instance = instance; @@ -673,6 +698,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) memset(cmd->io_request, 0, sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); cmd->io_request_phys_addr = io_req_base_phys + offset; + cmd->is_raid_1_fp_write = 0; } if (megasas_create_sg_sense_fusion(instance)) @@ -1262,12 +1288,12 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) fusion->reply_q_depth = 2 * (((max_cmd + 1 + 15)/16)*16); fusion->request_alloc_sz = - sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd; + sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * instance->max_mpt_cmds; fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION) *(fusion->reply_q_depth); fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + - (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * - (max_cmd + 1)); /* Extra 1 for SMID 0 */ + (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + * (instance->max_mpt_cmds + 1)); /* Extra 1 for SMID 0 */ scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2); /* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set, @@ -1403,42 +1429,43 @@ fail_alloc_mfi_cmds: */ void -map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status) +map_cmd_status(struct fusion_context *fusion, + struct scsi_cmnd *scmd, u8 status, u8 ext_status, + u32 data_length, u8 *sense) { switch (status) { case MFI_STAT_OK: - cmd->scmd->result = DID_OK << 16; + scmd->result = DID_OK << 16; break; case MFI_STAT_SCSI_IO_FAILED: case MFI_STAT_LD_INIT_IN_PROGRESS: - cmd->scmd->result = (DID_ERROR << 16) | ext_status; + scmd->result = (DID_ERROR << 16) | ext_status; break; case MFI_STAT_SCSI_DONE_WITH_ERROR: - cmd->scmd->result = (DID_OK << 16) | ext_status; + scmd->result = (DID_OK << 16) | ext_status; if (ext_status == SAM_STAT_CHECK_CONDITION) { - memset(cmd->scmd->sense_buffer, 0, + memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - memcpy(cmd->scmd->sense_buffer, cmd->sense, + memcpy(scmd->sense_buffer, sense, SCSI_SENSE_BUFFERSIZE); - cmd->scmd->result |= DRIVER_SENSE << 24; + scmd->result |= DRIVER_SENSE << 24; } break; case MFI_STAT_LD_OFFLINE: case MFI_STAT_DEVICE_NOT_FOUND: - cmd->scmd->result = DID_BAD_TARGET << 16; + scmd->result = DID_BAD_TARGET << 16; break; case MFI_STAT_CONFIG_SEQ_MISMATCH: - cmd->scmd->result = DID_IMM_RETRY << 16; + scmd->result = DID_IMM_RETRY << 16; break; default: - dev_printk(KERN_DEBUG, &cmd->instance->pdev->dev, "FW status %#x\n", status); - cmd->scmd->result = DID_ERROR << 16; + scmd->result = DID_ERROR << 16; break; } } @@ -1881,6 +1908,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo; io_info.numBlocks = datalength; io_info.ldTgtId = device_id; + io_info.r1_alt_dev_handle = MR_PD_INVALID; io_request->DataLength = cpu_to_le32(scsi_bufflen(scp)); if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) @@ -1949,6 +1977,10 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, } else scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; + cmd->is_raid_1_fp_write = io_info.is_raid_1_fp_write; + if (io_info.is_raid_1_fp_write) + cmd->r1_alt_dev_handle = io_info.r1_alt_dev_handle; + if ((raidLUN[0] == 1) && (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) { instance->dev_handle = !(instance->dev_handle); @@ -2272,19 +2304,118 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index) u8 *p; struct fusion_context *fusion; - if (index >= instance->max_fw_cmds) { + if (index >= instance->max_mpt_cmds) { dev_err(&instance->pdev->dev, "Invalid SMID (0x%x)request for " "descriptor for scsi%d\n", index, instance->host->host_no); return NULL; } fusion = instance->ctrl_context; - p = fusion->req_frames_desc - +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index; + p = fusion->req_frames_desc + + sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * index; return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p; } +/* + * megasas_fpio_to_ldio- + * This function converts an fp io to ldio + */ + +void megasas_fpio_to_ldio(struct megasas_instance *instance, + struct megasas_cmd_fusion *cmd, struct scsi_cmnd *scmd) +{ + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + cmd->request_desc->SCSIIO.RequestFlags = + (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO + << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + cmd->io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; + cmd->io_request->DevHandle = cpu_to_le16(MEGASAS_DEV_INDEX(scmd)); + + /*remove FAST PATH ENABLE bit in IoFlags */ + cmd->io_request->IoFlags &= + cpu_to_le16(~MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); + + /* if the numSGE > max_sge_in_main_sge set the chain offset*/ + if (cmd->io_request->RaidContext.raid_context_g35.num_sge > + fusion->max_sge_in_main_msg) + cmd->io_request->ChainOffset = fusion->chain_offset_io_request; + memcpy(cmd->io_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); + cmd->io_request->CDB.EEDP32.PrimaryReferenceTag = 0; + cmd->io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0; + cmd->io_request->EEDPFlags = 0; + cmd->io_request->Control = 0; + cmd->io_request->EEDPBlockSize = 0; + cmd->is_raid_1_fp_write = 0; +} + +/* megasas_prepate_secondRaid1_IO + * It prepares the raid 1 second IO + */ +void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance, + struct megasas_cmd_fusion *cmd, + struct megasas_cmd_fusion *r1_cmd) +{ + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, *req_desc2 = NULL; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + req_desc = cmd->request_desc; + if (r1_cmd) { + /* copy the io request frame as well + * as 8 SGEs data for r1 command + */ + memcpy(r1_cmd->io_request, cmd->io_request, + sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); + memcpy(&r1_cmd->io_request->SGL, &cmd->io_request->SGL, + (fusion->max_sge_in_main_msg * + sizeof(union MPI2_SGE_IO_UNION))); + /*sense buffer is different for r1 command*/ + r1_cmd->io_request->SenseBufferLowAddress = + cpu_to_le32(r1_cmd->sense_phys_addr); + r1_cmd->scmd = cmd->scmd; + req_desc2 = + megasas_get_request_descriptor(instance, r1_cmd->index-1); + if (req_desc2) { + req_desc2->Words = 0; + r1_cmd->request_desc = req_desc2; + req_desc2->SCSIIO.SMID = + cpu_to_le16(r1_cmd->index); + req_desc2->SCSIIO.RequestFlags = + req_desc->SCSIIO.RequestFlags; + r1_cmd->is_raid_1_fp_write = 1; + r1_cmd->request_desc->SCSIIO.DevHandle = + cmd->r1_alt_dev_handle; + r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle; + cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid = + cpu_to_le16(r1_cmd->index); + r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid = + cpu_to_le16(cmd->index); + /* MSIxIndex of both commands request + * descriptors should be same + */ + r1_cmd->request_desc->SCSIIO.MSIxIndex = + cmd->request_desc->SCSIIO.MSIxIndex; + /*span arm is different for r1 cmd*/ + r1_cmd->io_request->RaidContext.raid_context_g35.span_arm = + cmd->io_request->RaidContext.raid_context_g35.span_arm + 1; + } else { + megasas_return_cmd_fusion(instance, r1_cmd); + dev_info(&instance->pdev->dev, + "unable to get request descriptor, firing as normal IO\n"); + atomic_dec(&instance->fw_outstanding); + megasas_fpio_to_ldio(instance, cmd, cmd->scmd); + } + } else { + dev_info(&instance->pdev->dev, + "unable to get command, firing as normal IO\n"); + atomic_dec(&instance->fw_outstanding); + megasas_fpio_to_ldio(instance, cmd, cmd->scmd); + } +} + /** * megasas_build_and_issue_cmd_fusion -Main routine for building and * issuing non IOCTL cmd @@ -2295,7 +2426,7 @@ static u32 megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, struct scsi_cmnd *scmd) { - struct megasas_cmd_fusion *cmd; + struct megasas_cmd_fusion *cmd, *r1_cmd = NULL; union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; u32 index; struct fusion_context *fusion; @@ -2310,13 +2441,27 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, return SCSI_MLQUEUE_DEVICE_BUSY; } + if (atomic_inc_return(&instance->fw_outstanding) > + instance->host->can_queue) { + dev_err(&instance->pdev->dev, "Throttle IOs beyond Controller queue depth\n"); + atomic_dec(&instance->fw_outstanding); + return SCSI_MLQUEUE_HOST_BUSY; + } + cmd = megasas_get_cmd_fusion(instance, scmd->request->tag); + if (!cmd) { + atomic_dec(&instance->fw_outstanding); + return SCSI_MLQUEUE_HOST_BUSY; + } + index = cmd->index; req_desc = megasas_get_request_descriptor(instance, index-1); - if (!req_desc) + if (!req_desc) { + atomic_dec(&instance->fw_outstanding); return SCSI_MLQUEUE_HOST_BUSY; + } req_desc->Words = 0; cmd->request_desc = req_desc; @@ -2325,6 +2470,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, megasas_return_cmd_fusion(instance, cmd); dev_err(&instance->pdev->dev, "Error building command\n"); cmd->request_desc = NULL; + atomic_dec(&instance->fw_outstanding); return SCSI_MLQUEUE_HOST_BUSY; } @@ -2335,14 +2481,39 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, cmd->io_request->ChainOffset != 0xF) dev_err(&instance->pdev->dev, "The chain offset value is not " "correct : %x\n", cmd->io_request->ChainOffset); + /* + * if it is raid 1/10 fp write capable. + * try to get second command from pool and construct it. + * From FW, it has confirmed that lba values of two PDs + * corresponds to single R1/10 LD are always same + * + */ + /* driver side count always should be less than max_fw_cmds + * to get new command + */ + if (cmd->is_raid_1_fp_write && + atomic_inc_return(&instance->fw_outstanding) > + (instance->host->can_queue)) { + megasas_fpio_to_ldio(instance, cmd, cmd->scmd); + atomic_dec(&instance->fw_outstanding); + } else if (cmd->is_raid_1_fp_write) { + r1_cmd = megasas_get_cmd_fusion(instance, + (scmd->request->tag + instance->max_fw_cmds)); + megasas_prepare_secondRaid1_IO(instance, cmd, r1_cmd); + } + /* * Issue the command to the FW */ - atomic_inc(&instance->fw_outstanding); megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura); + if (r1_cmd) + megasas_fire_cmd_fusion(instance, r1_cmd->request_desc, + instance->is_ventura); + + return 0; } @@ -2359,10 +2530,10 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req; struct fusion_context *fusion; struct megasas_cmd *cmd_mfi; - struct megasas_cmd_fusion *cmd_fusion; + struct megasas_cmd_fusion *cmd_fusion, *r1_cmd = NULL; u16 smid, num_completed; - u8 reply_descript_type; - u32 status, extStatus, device_id; + u8 reply_descript_type, *sense; + u32 status, extStatus, device_id, data_length; union desc_value d_val; struct LD_LOAD_BALANCE_INFO *lbinfo; int threshold_reply_count = 0; @@ -2392,6 +2563,15 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) while (d_val.u.low != cpu_to_le32(UINT_MAX) && d_val.u.high != cpu_to_le32(UINT_MAX)) { + /* + * Ensure that the peer command is NULL here in case a + * command has completed but the R1 FP Write peer has + * not completed yet.If not null, it's possible that + * another thread will complete the peer + * command and should not. + */ + r1_cmd = NULL; + smid = le16_to_cpu(reply_desc->SMID); cmd_fusion = fusion->cmd_list[smid - 1]; @@ -2406,6 +2586,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) scmd_local = cmd_fusion->scmd; status = scsi_io_req->RaidContext.raid_context.status; extStatus = scsi_io_req->RaidContext.raid_context.exStatus; + sense = cmd_fusion->sense; + data_length = scsi_io_req->DataLength; switch (scsi_io_req->Function) { case MPI2_FUNCTION_SCSI_TASK_MGMT: @@ -2422,12 +2604,28 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) /* Update load balancing info */ device_id = MEGASAS_DEV_INDEX(scmd_local); lbinfo = &fusion->load_balance_info[device_id]; - if (cmd_fusion->scmd->SCp.Status & - MEGASAS_LOAD_BALANCE_FLAG) { + /* + * check for the raid 1/10 fast path writes + */ + if (!cmd_fusion->is_raid_1_fp_write && + (cmd_fusion->scmd->SCp.Status & + MEGASAS_LOAD_BALANCE_FLAG)) { atomic_dec(&lbinfo->scsi_pending_cmds[cmd_fusion->pd_r1_lb]); cmd_fusion->scmd->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; + } else if (cmd_fusion->is_raid_1_fp_write) { + /* get peer command */ + if (cmd_fusion->index < instance->max_fw_cmds) + r1_cmd = fusion->cmd_list[(cmd_fusion->index + + instance->max_fw_cmds)-1]; + else { + r1_cmd = + fusion->cmd_list[(cmd_fusion->index - + instance->max_fw_cmds)-1]; + } + cmd_fusion->cmd_completed = true; } + if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { if (megasas_dbg_lvl == 5) @@ -2437,14 +2635,48 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) /* Fall thru and complete IO */ case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */ /* Map the FW Cmd Status */ - map_cmd_status(cmd_fusion, status, extStatus); - scsi_io_req->RaidContext.raid_context.status = 0; - scsi_io_req->RaidContext.raid_context.exStatus = 0; - if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) - atomic_dec(&instance->ldio_outstanding); - megasas_return_cmd_fusion(instance, cmd_fusion); - scsi_dma_unmap(scmd_local); - scmd_local->scsi_done(scmd_local); + /* + * check for the raid 1/10 fast path writes + */ + if (r1_cmd && r1_cmd->is_raid_1_fp_write + && r1_cmd->cmd_completed) { + /* + * if the peer Raid 1/10 fast path failed, + * mark IO as failed to the scsi layer. + * over write the current status by the failed + * status makes sure that if any one of + * command fails,return fail status to + * scsi layer + */ + if (r1_cmd->io_request->RaidContext.raid_context.status != + MFI_STAT_OK) { + status = + r1_cmd->io_request->RaidContext.raid_context.status; + extStatus = + r1_cmd->io_request->RaidContext.raid_context.exStatus; + data_length = + r1_cmd->io_request->DataLength; + sense = r1_cmd->sense; + } + r1_cmd->io_request->RaidContext.raid_context.status = 0; + r1_cmd->io_request->RaidContext.raid_context.exStatus = 0; + cmd_fusion->is_raid_1_fp_write = 0; + r1_cmd->is_raid_1_fp_write = 0; + r1_cmd->cmd_completed = false; + cmd_fusion->cmd_completed = false; + megasas_return_cmd_fusion(instance, r1_cmd); + } + if (!cmd_fusion->is_raid_1_fp_write) { + map_cmd_status(fusion, scmd_local, status, + extStatus, data_length, sense); + scsi_io_req->RaidContext.raid_context.status + = 0; + scsi_io_req->RaidContext.raid_context.exStatus + = 0; + megasas_return_cmd_fusion(instance, cmd_fusion); + scsi_dma_unmap(scmd_local); + scmd_local->scsi_done(scmd_local); + } atomic_dec(&instance->fw_outstanding); break; @@ -3497,7 +3729,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) { int retval = SUCCESS, i, j, convert = 0; struct megasas_instance *instance; - struct megasas_cmd_fusion *cmd_fusion; + struct megasas_cmd_fusion *cmd_fusion, *mpt_cmd_fusion; struct fusion_context *fusion; u32 abs_state, status_reg, reset_adapter; u32 io_timeout_in_crash_mode = 0; @@ -3572,6 +3804,18 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) /* Now return commands back to the OS */ for (i = 0 ; i < instance->max_scsi_cmds; i++) { cmd_fusion = fusion->cmd_list[i]; + /*check for extra commands issued by driver*/ + if (instance->is_ventura) { + cmd_fusion->is_raid_1_fp_write = 0; + cmd_fusion->cmd_completed = false; + mpt_cmd_fusion = + fusion->cmd_list[i + instance->max_fw_cmds]; + mpt_cmd_fusion->is_raid_1_fp_write = 0; + mpt_cmd_fusion->cmd_completed = false; + if (mpt_cmd_fusion->scmd) + megasas_return_cmd_fusion(instance, + mpt_cmd_fusion); + } scmd_local = cmd_fusion->scmd; if (cmd_fusion->scmd) { scmd_local->result = @@ -3582,10 +3826,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) megasas_return_cmd_fusion(instance, cmd_fusion); scsi_dma_unmap(scmd_local); scmd_local->scsi_done(scmd_local); - atomic_dec(&instance->fw_outstanding); } } + atomic_set(&instance->fw_outstanding, 0); + status_reg = instance->instancet->read_fw_status_reg( instance->reg_set); abs_state = status_reg & MFI_STATE_MASK; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 3909a26a5d31..3a5af3bb9989 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -94,6 +94,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { #define MEGASAS_FP_CMD_LEN 16 #define MEGASAS_FUSION_IN_RESET 0 #define THRESHOLD_REPLY_COUNT 50 +#define RAID_1_10_RMW_CMDS 3 #define JBOD_MAPS_COUNT 2 enum MR_FUSION_ADAPTER_TYPE { @@ -728,7 +729,9 @@ struct MR_SPAN_BLOCK_INFO { struct MR_LD_RAID { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved4:5; + u32 reserved4:3; + u32 fp_cache_bypass_capable:1; + u32 fp_rmw_capable:1; u32 fpBypassRegionLock:1; u32 tmCapable:1; u32 fpNonRWCapable:1; @@ -756,7 +759,9 @@ struct MR_LD_RAID { u32 fpNonRWCapable:1; u32 tmCapable:1; u32 fpBypassRegionLock:1; - u32 reserved4:5; + u32 fp_rmw_capable:1; + u32 fp_cache_bypass_capable:1; + u32 reserved4:3; #endif } capability; __le32 reserved6; @@ -830,6 +835,8 @@ struct IO_REQUEST_INFO { u64 start_row; u8 span_arm; /* span[7:5], arm[4:0] */ u8 pd_after_lb; + u16 r1_alt_dev_handle; /* raid 1/10 only */ + bool is_raid_1_fp_write; bool ra_capable; }; @@ -883,6 +890,10 @@ struct megasas_cmd_fusion { u32 index; u8 pd_r1_lb; struct completion done; + bool is_raid_1_fp_write; + u16 r1_alt_dev_handle; /* raid 1/10 only*/ + bool cmd_completed; /* raid 1/10 fp writes status holder */ + }; struct LD_LOAD_BALANCE_INFO { From d889344e4e59eb962894ab3b64042dc37a2d8b39 Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:48 -0500 Subject: [PATCH 0338/1587] scsi: megaraid_sas: Dynamic Raid Map Changes for SAS3.5 Generic Megaraid Controllers SAS3.5 Generic Megaraid Controllers FW will support new dynamic RaidMap to have different sizes for different number of supported VDs. Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 7 + drivers/scsi/megaraid/megaraid_sas_base.c | 58 ++-- drivers/scsi/megaraid/megaraid_sas_fp.c | 301 +++++++++++++++++--- drivers/scsi/megaraid/megaraid_sas_fusion.c | 225 ++++++++++++--- drivers/scsi/megaraid/megaraid_sas_fusion.h | 240 +++++++++++++--- 5 files changed, 694 insertions(+), 137 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index a96889c34db0..6ddf994a25b7 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1434,6 +1434,12 @@ enum FW_BOOT_CONTEXT { #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14 #define MR_MAX_MSIX_REG_ARRAY 16 #define MR_RDPQ_MODE_OFFSET 0X00800000 + +#define MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT 16 +#define MR_MAX_RAID_MAP_SIZE_MASK 0x1FF +#define MR_MIN_MAP_SIZE 0x10000 +/* 64k */ + #define MR_CAN_HANDLE_SYNC_CACHE_OFFSET 0X01000000 /* @@ -2151,6 +2157,7 @@ struct megasas_instance { bool fw_sync_cache_support; bool is_ventura; bool msix_combined; + u16 max_raid_mapsize; }; struct MR_LD_VF_MAP { u32 size; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index b2b1d29ec942..fd6ddde43d03 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4424,8 +4424,7 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) static void megasas_update_ext_vd_details(struct megasas_instance *instance) { struct fusion_context *fusion; - u32 old_map_sz; - u32 new_map_sz; + u32 ventura_map_sz = 0; fusion = instance->ctrl_context; /* For MFI based controllers return dummy success */ @@ -4455,21 +4454,38 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance) instance->supportmax256vd ? "Extended VD(240 VD)firmware" : "Legacy(64 VD) firmware"); - old_map_sz = sizeof(struct MR_FW_RAID_MAP) + - (sizeof(struct MR_LD_SPAN_MAP) * - (instance->fw_supported_vd_count - 1)); - new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); - fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP) + - (sizeof(struct MR_LD_SPAN_MAP) * - (instance->drv_supported_vd_count - 1)); + if (instance->max_raid_mapsize) { + ventura_map_sz = instance->max_raid_mapsize * + MR_MIN_MAP_SIZE; /* 64k */ + fusion->current_map_sz = ventura_map_sz; + fusion->max_map_sz = ventura_map_sz; + } else { + fusion->old_map_sz = sizeof(struct MR_FW_RAID_MAP) + + (sizeof(struct MR_LD_SPAN_MAP) * + (instance->fw_supported_vd_count - 1)); + fusion->new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); - fusion->max_map_sz = max(old_map_sz, new_map_sz); + fusion->max_map_sz = + max(fusion->old_map_sz, fusion->new_map_sz); + if (instance->supportmax256vd) + fusion->current_map_sz = fusion->new_map_sz; + else + fusion->current_map_sz = fusion->old_map_sz; + } + /* irrespective of FW raid maps, driver raid map is constant */ + fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP_ALL); - if (instance->supportmax256vd) - fusion->current_map_sz = new_map_sz; - else - fusion->current_map_sz = old_map_sz; +#if VD_EXT_DEBUG + dev_info(&instance->pdev->dev, "instance->max_raid_mapsize 0x%x\n ", + instance->max_raid_mapsize); + dev_info(&instance->pdev->dev, "new_map_sz = 0x%x, old_map_sz = 0x%x\n", + fusion->new_map_sz, fusion->old_map_sz); + dev_info(&instance->pdev->dev, "ventura_map_sz = 0x%x, current_map_sz = 0x%x\n", + ventura_map_sz, fusion->current_map_sz); + dev_info(&instance->pdev->dev, "fusion->drv_map_sz =0x%x, size of driver raid map 0x%lx\n", + fusion->drv_map_sz, sizeof(struct MR_DRV_RAID_MAP_ALL)); +#endif } /** @@ -4996,7 +5012,7 @@ static int megasas_init_fw(struct megasas_instance *instance) { u32 max_sectors_1; u32 max_sectors_2; - u32 tmp_sectors, msix_enable, scratch_pad_2; + u32 tmp_sectors, msix_enable, scratch_pad_2, scratch_pad_3; resource_size_t base_addr; struct megasas_register_set __iomem *reg_set; struct megasas_ctrl_info *ctrl_info = NULL; @@ -5072,7 +5088,17 @@ static int megasas_init_fw(struct megasas_instance *instance) goto fail_ready_state; } - + if (instance->is_ventura) { + scratch_pad_3 = + readl(&instance->reg_set->outbound_scratch_pad_3); +#if VD_EXT_DEBUG + dev_info(&instance->pdev->dev, "scratch_pad3 0x%x\n", + scratch_pad_3); +#endif + instance->max_raid_mapsize = ((scratch_pad_3 >> + MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) & + MR_MAX_RAID_MAP_SIZE_MASK); + } /* Check if MSI-X is supported while in ready state */ msix_enable = (instance->instancet->read_fw_status_reg(reg_set) & diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index eb9ff444c099..f1384b01b3d3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -179,18 +179,204 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) struct fusion_context *fusion = instance->ctrl_context; struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL; struct MR_FW_RAID_MAP *pFwRaidMap = NULL; - int i; + int i, j; u16 ld_count; + struct MR_FW_RAID_MAP_DYNAMIC *fw_map_dyn; + struct MR_FW_RAID_MAP_EXT *fw_map_ext; + struct MR_RAID_MAP_DESC_TABLE *desc_table; struct MR_DRV_RAID_MAP_ALL *drv_map = fusion->ld_drv_map[(instance->map_id & 1)]; struct MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap; + void *raid_map_data = NULL; + + memset(drv_map, 0, fusion->drv_map_sz); + memset(pDrvRaidMap->ldTgtIdToLd, + 0xff, (sizeof(u16) * MAX_LOGICAL_DRIVES_DYN)); + + if (instance->max_raid_mapsize) { + fw_map_dyn = fusion->ld_map[(instance->map_id & 1)]; +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "raidMapSize 0x%x fw_map_dyn->descTableOffset 0x%x\n", + le32_to_cpu(fw_map_dyn->raid_map_size), + le32_to_cpu(fw_map_dyn->desc_table_offset)); + dev_dbg(&instance->pdev->dev, "descTableSize 0x%x descTableNumElements 0x%x\n", + le32_to_cpu(fw_map_dyn->desc_table_size), + le32_to_cpu(fw_map_dyn->desc_table_num_elements)); + dev_dbg(&instance->pdev->dev, "drv map %p ldCount %d\n", + drv_map, fw_map_dyn->ld_count); +#endif + desc_table = + (struct MR_RAID_MAP_DESC_TABLE *)((void *)fw_map_dyn + le32_to_cpu(fw_map_dyn->desc_table_offset)); + if (desc_table != fw_map_dyn->raid_map_desc_table) + dev_dbg(&instance->pdev->dev, "offsets of desc table are not matching desc %p original %p\n", + desc_table, fw_map_dyn->raid_map_desc_table); + + ld_count = (u16)le16_to_cpu(fw_map_dyn->ld_count); + pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); + pDrvRaidMap->fpPdIoTimeoutSec = + fw_map_dyn->fp_pd_io_timeout_sec; + pDrvRaidMap->totalSize = sizeof(struct MR_DRV_RAID_MAP_ALL); + /* point to actual data starting point*/ + raid_map_data = (void *)fw_map_dyn + + le32_to_cpu(fw_map_dyn->desc_table_offset) + + le32_to_cpu(fw_map_dyn->desc_table_size); + + for (i = 0; i < le32_to_cpu(fw_map_dyn->desc_table_num_elements); ++i) { + +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "desc table %p\n", + desc_table); + dev_dbg(&instance->pdev->dev, "raidmap type %d, raidmapOffset 0x%x\n", + desc_table->raid_map_desc_type, + desc_table->raid_map_desc_offset); + dev_dbg(&instance->pdev->dev, "raid map number of elements 0%x, raidmapsize 0x%x\n", + desc_table->raid_map_desc_elements, + desc_table->raid_map_desc_buffer_size); +#endif + switch (le32_to_cpu(desc_table->raid_map_desc_type)) { + case RAID_MAP_DESC_TYPE_DEVHDL_INFO: + fw_map_dyn->dev_hndl_info = + (struct MR_DEV_HANDLE_INFO *)(raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "devHndlInfo address %p\n", + fw_map_dyn->dev_hndl_info); +#endif + memcpy(pDrvRaidMap->devHndlInfo, + fw_map_dyn->dev_hndl_info, + sizeof(struct MR_DEV_HANDLE_INFO) * + le32_to_cpu(desc_table->raid_map_desc_elements)); + break; + case RAID_MAP_DESC_TYPE_TGTID_INFO: + fw_map_dyn->ld_tgt_id_to_ld = + (u16 *) (raid_map_data + + le32_to_cpu(desc_table->raid_map_desc_offset)); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "ldTgtIdToLd address %p\n", + fw_map_dyn->ld_tgt_id_to_ld); +#endif + for (j = 0; j < le32_to_cpu(desc_table->raid_map_desc_elements); j++) { + pDrvRaidMap->ldTgtIdToLd[j] = + fw_map_dyn->ld_tgt_id_to_ld[j]; +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, " %d drv ldTgtIdToLd %d\n", + j, pDrvRaidMap->ldTgtIdToLd[j]); +#endif + } + break; + case RAID_MAP_DESC_TYPE_ARRAY_INFO: + fw_map_dyn->ar_map_info = + (struct MR_ARRAY_INFO *) + (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "arMapInfo address %p\n", + fw_map_dyn->ar_map_info); +#endif + + memcpy(pDrvRaidMap->arMapInfo, + fw_map_dyn->ar_map_info, + sizeof(struct MR_ARRAY_INFO) * le32_to_cpu(desc_table->raid_map_desc_elements)); + break; + case RAID_MAP_DESC_TYPE_SPAN_INFO: + fw_map_dyn->ld_span_map = + (struct MR_LD_SPAN_MAP *) + (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); + memcpy(pDrvRaidMap->ldSpanMap, + fw_map_dyn->ld_span_map, + sizeof(struct MR_LD_SPAN_MAP) * le32_to_cpu(desc_table->raid_map_desc_elements)); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "ldSpanMap address %p\n", + fw_map_dyn->ld_span_map); + dev_dbg(&instance->pdev->dev, "MR_LD_SPAN_MAP size 0x%lx\n", + sizeof(struct MR_LD_SPAN_MAP)); + for (j = 0; j < ld_count; j++) { + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : fw_map_dyn->ldSpanMap[%d].ldRaid.targetId 0x%x\n", + j, j, fw_map_dyn->ld_span_map[j].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "fw_map_dyn->ldSpanMap[%d].ldRaid.seqNum 0x%x\n", + j, fw_map_dyn->ld_span_map[j].ldRaid.seqNum); + dev_dbg(&instance->pdev->dev, "fw_map_dyn->ld_span_map[%d].ldRaid.rowSize 0x%x\n", + j, (u32)fw_map_dyn->ld_span_map[j].ldRaid.rowSize); + + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) :pDrvRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x\n", + j, j, pDrvRaidMap->ldSpanMap[j].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "DrvRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x\n", + j, pDrvRaidMap->ldSpanMap[j].ldRaid.seqNum); + dev_dbg(&instance->pdev->dev, "pDrvRaidMap->ldSpanMap[%d].ldRaid.rowSize 0x%x\n", + j, (u32)pDrvRaidMap->ldSpanMap[j].ldRaid.rowSize); + + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : drv raid map all %p\n", + instance->unique_id, drv_map); + dev_dbg(&instance->pdev->dev, "raid map %p LD RAID MAP %p/%p\n", + pDrvRaidMap, + &fw_map_dyn->ld_span_map[j].ldRaid, + &pDrvRaidMap->ldSpanMap[j].ldRaid); + } +#endif + break; + default: + dev_dbg(&instance->pdev->dev, "wrong number of desctableElements %d\n", + fw_map_dyn->desc_table_num_elements); + } + ++desc_table; + } + + } else if (instance->supportmax256vd) { + fw_map_ext = + (struct MR_FW_RAID_MAP_EXT *) fusion->ld_map[(instance->map_id & 1)]; + ld_count = (u16)le16_to_cpu(fw_map_ext->ldCount); + if (ld_count > MAX_LOGICAL_DRIVES_EXT) { + dev_dbg(&instance->pdev->dev, "megaraid_sas: LD count exposed in RAID map in not valid\n"); + return; + } +#if VD_EXT_DEBUG + for (i = 0; i < ld_count; i++) { + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) :Index 0x%x\n", + instance->unique_id, i); + dev_dbg(&instance->pdev->dev, "Target Id 0x%x\n", + fw_map_ext->ldSpanMap[i].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "Seq Num 0x%x Size 0/%llx\n", + fw_map_ext->ldSpanMap[i].ldRaid.seqNum, + fw_map_ext->ldSpanMap[i].ldRaid.size); + } +#endif + + pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); + pDrvRaidMap->fpPdIoTimeoutSec = fw_map_ext->fpPdIoTimeoutSec; + for (i = 0; i < (MAX_LOGICAL_DRIVES_EXT); i++) + pDrvRaidMap->ldTgtIdToLd[i] = + (u16)fw_map_ext->ldTgtIdToLd[i]; + memcpy(pDrvRaidMap->ldSpanMap, fw_map_ext->ldSpanMap, + sizeof(struct MR_LD_SPAN_MAP) * ld_count); +#if VD_EXT_DEBUG + for (i = 0; i < ld_count; i++) { + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : fw_map_ext->ldSpanMap[%d].ldRaid.targetId 0x%x\n", + i, i, fw_map_ext->ldSpanMap[i].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "fw_map_ext->ldSpanMap[%d].ldRaid.seqNum 0x%x\n", + i, fw_map_ext->ldSpanMap[i].ldRaid.seqNum); + dev_dbg(&instance->pdev->dev, "fw_map_ext->ldSpanMap[%d].ldRaid.rowSize 0x%x\n", + i, (u32)fw_map_ext->ldSpanMap[i].ldRaid.rowSize); + + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : pDrvRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x\n", + i, i, pDrvRaidMap->ldSpanMap[i].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "pDrvRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x\n", + i, pDrvRaidMap->ldSpanMap[i].ldRaid.seqNum); + dev_dbg(&instance->pdev->dev, "pDrvRaidMap->ldSpanMap[%d].ldRaid.rowSize 0x%x\n", + i, (u32)pDrvRaidMap->ldSpanMap[i].ldRaid.rowSize); + + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : drv raid map all %p\n", + instance->unique_id, drv_map); + dev_dbg(&instance->pdev->dev, "raid map %p LD RAID MAP %p %p\n", + pDrvRaidMap, &fw_map_ext->ldSpanMap[i].ldRaid, + &pDrvRaidMap->ldSpanMap[i].ldRaid); + } +#endif + memcpy(pDrvRaidMap->arMapInfo, fw_map_ext->arMapInfo, + sizeof(struct MR_ARRAY_INFO) * MAX_API_ARRAYS_EXT); + memcpy(pDrvRaidMap->devHndlInfo, fw_map_ext->devHndlInfo, + sizeof(struct MR_DEV_HANDLE_INFO) * + MAX_RAIDMAP_PHYSICAL_DEVICES); - if (instance->supportmax256vd) { - memcpy(fusion->ld_drv_map[instance->map_id & 1], - fusion->ld_map[instance->map_id & 1], - fusion->current_map_sz); /* New Raid map will not set totalSize, so keep expected value * for legacy code in ValidateMapInfo */ @@ -213,16 +399,12 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) } #endif - memset(drv_map, 0, fusion->drv_map_sz); pDrvRaidMap->totalSize = pFwRaidMap->totalSize; pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec; for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) pDrvRaidMap->ldTgtIdToLd[i] = (u8)pFwRaidMap->ldTgtIdToLd[i]; - for (i = (MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS); - i < MAX_LOGICAL_DRIVES_EXT; i++) - pDrvRaidMap->ldTgtIdToLd[i] = 0xff; for (i = 0; i < ld_count; i++) { pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i]; #if VD_EXT_DEBUG @@ -279,7 +461,9 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance) lbInfo = fusion->load_balance_info; ldSpanInfo = fusion->log_to_span; - if (instance->supportmax256vd) + if (instance->max_raid_mapsize) + expected_size = sizeof(struct MR_DRV_RAID_MAP_ALL); + else if (instance->supportmax256vd) expected_size = sizeof(struct MR_FW_RAID_MAP_EXT); else expected_size = @@ -287,8 +471,10 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance) (sizeof(struct MR_LD_SPAN_MAP) * le16_to_cpu(pDrvRaidMap->ldCount))); if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) { - dev_err(&instance->pdev->dev, "map info structure size 0x%x is not matching with ld count\n", - (unsigned int) expected_size); + dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x", + le32_to_cpu(pDrvRaidMap->totalSize)); + dev_dbg(&instance->pdev->dev, "is not matching expected size 0x%x\n", + (unsigned int) expected_size); dev_err(&instance->pdev->dev, "megasas: span map %x, pDrvRaidMap->totalSize : %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP), le32_to_cpu(pDrvRaidMap->totalSize)); @@ -787,7 +973,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, ((fusion->adapter_type == THUNDERBOLT_SERIES) || ((fusion->adapter_type == INVADER_SERIES) && (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) - pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; + pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { physArm = physArm + 1; pd = MR_ArPdGet(arRef, physArm, map); @@ -797,9 +983,16 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, } *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); - pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | - physArm; - io_info->span_arm = pRAID_Context->spanArm; + if (instance->is_ventura) { + ((struct RAID_CONTEXT_G35 *) pRAID_Context)->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + io_info->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + } else { + pRAID_Context->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + io_info->span_arm = pRAID_Context->span_arm; + } return retval; } @@ -891,7 +1084,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, ((fusion->adapter_type == THUNDERBOLT_SERIES) || ((fusion->adapter_type == INVADER_SERIES) && (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) - pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; + pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { /* Get alternate Pd. */ physArm = physArm + 1; @@ -903,9 +1096,16 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, } *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); - pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | - physArm; - io_info->span_arm = pRAID_Context->spanArm; + if (instance->is_ventura) { + ((struct RAID_CONTEXT_G35 *) pRAID_Context)->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + io_info->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + } else { + pRAID_Context->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + io_info->span_arm = pRAID_Context->span_arm; + } return retval; } @@ -1109,20 +1309,20 @@ MR_BuildRaidContext(struct megasas_instance *instance, regSize += stripSize; } - pRAID_Context->timeoutValue = + pRAID_Context->timeout_value = cpu_to_le16(raid->fpIoTimeoutForLd ? raid->fpIoTimeoutForLd : map->raidMap.fpPdIoTimeoutSec); if (fusion->adapter_type == INVADER_SERIES) - pRAID_Context->regLockFlags = (isRead) ? + pRAID_Context->reg_lock_flags = (isRead) ? raid->regTypeReqOnRead : raid->regTypeReqOnWrite; - else - pRAID_Context->regLockFlags = (isRead) ? + else if (!instance->is_ventura) + pRAID_Context->reg_lock_flags = (isRead) ? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; - pRAID_Context->VirtualDiskTgtId = raid->targetId; - pRAID_Context->regLockRowLBA = cpu_to_le64(regStart); - pRAID_Context->regLockLength = cpu_to_le32(regSize); - pRAID_Context->configSeqNum = raid->seqNum; + pRAID_Context->virtual_disk_tgt_id = raid->targetId; + pRAID_Context->reg_lock_row_lba = cpu_to_le64(regStart); + pRAID_Context->reg_lock_length = cpu_to_le32(regSize); + pRAID_Context->config_seq_num = raid->seqNum; /* save pointer to raid->LUN array */ *raidLUN = raid->LUN; @@ -1140,6 +1340,13 @@ MR_BuildRaidContext(struct megasas_instance *instance, /* If IO on an invalid Pd, then FP is not possible.*/ if (io_info->devHandle == cpu_to_le16(MR_PD_INVALID)) io_info->fpOkForIo = FALSE; + /* if FP possible, set the SLUD bit in + * regLockFlags for ventura + */ + else if ((instance->is_ventura) && (!isRead) && + (raid->writeMode == MR_RL_WRITE_BACK_MODE) && + (raid->capability.fp_cache_bypass_capable)) + ((struct RAID_CONTEXT_G35 *) pRAID_Context)->routing_flags.bits.sld = 1; /* set raid 1/10 fast path write capable bit in io_info */ if (io_info->fpOkForIo && (io_info->r1_alt_dev_handle != MR_PD_INVALID) && @@ -1319,6 +1526,7 @@ u8 megasas_get_best_arm_pd(struct megasas_instance *instance, struct fusion_context *fusion; struct MR_LD_RAID *raid; struct MR_DRV_RAID_MAP_ALL *drv_map; + u16 pd1_dev_handle; u16 pend0, pend1, ld; u64 diff0, diff1; u8 bestArm, pd0, pd1, span, arm; @@ -1344,23 +1552,36 @@ u8 megasas_get_best_arm_pd(struct megasas_instance *instance, pd1 = MR_ArPdGet(arRef, (arm + 1) >= span_row_size ? (arm + 1 - span_row_size) : arm + 1, drv_map); - /* get the pending cmds for the data and mirror arms */ - pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]); - pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]); + /* Get PD1 Dev Handle */ - /* Determine the disk whose head is nearer to the req. block */ - diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]); - diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]); - bestArm = (diff0 <= diff1 ? arm : arm ^ 1); + pd1_dev_handle = MR_PdDevHandleGet(pd1, drv_map); - if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds) || + if (pd1_dev_handle == MR_PD_INVALID) { + bestArm = arm; + } else { + /* get the pending cmds for the data and mirror arms */ + pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]); + pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]); + + /* Determine the disk whose head is nearer to the req. block */ + diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]); + diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]); + bestArm = (diff0 <= diff1 ? arm : arm ^ 1); + + /* Make balance count from 16 to 4 to + * keep driver in sync with Firmware + */ + if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds) || (bestArm != arm && pend1 > pend0 + lb_pending_cmds)) - bestArm ^= 1; + bestArm ^= 1; + + /* Update the last accessed block on the correct pd */ + io_info->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm; + io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1; + } - /* Update the last accessed block on the correct pd */ - io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1; lbInfo->last_accessed_block[io_info->pd_after_lb] = block + count - 1; - io_info->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm; #if SPAN_DEBUG if (arm != bestArm) dev_dbg(&instance->pdev->dev, "LSI Debug R1 Load balance " diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 792f26918ed6..29e883fa3ead 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1829,7 +1829,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, struct megasas_cmd_fusion *cmd) { u8 fp_possible; - u32 start_lba_lo, start_lba_hi, device_id, datalength = 0; + u32 start_lba_lo, start_lba_hi, device_id, datalength = 0, ld; struct MPI2_RAID_SCSI_IO_REQUEST *io_request; union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; struct IO_REQUEST_INFO io_info; @@ -1837,16 +1837,18 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, struct MR_DRV_RAID_MAP_ALL *local_map_ptr; u8 *raidLUN; unsigned long spinlock_flags; + union RAID_CONTEXT_UNION *praid_context; + struct MR_LD_RAID *raid; device_id = MEGASAS_DEV_INDEX(scp); fusion = instance->ctrl_context; io_request = cmd->io_request; - io_request->RaidContext.raid_context.VirtualDiskTgtId = + io_request->RaidContext.raid_context.virtual_disk_tgt_id = cpu_to_le16(device_id); io_request->RaidContext.raid_context.status = 0; - io_request->RaidContext.raid_context.exStatus = 0; + io_request->RaidContext.raid_context.ex_status = 0; req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc; @@ -1915,10 +1917,12 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, io_info.isRead = 1; local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; + ld = MR_TargetIdToLdGet(device_id, local_map_ptr); + raid = MR_LdRaidGet(ld, local_map_ptr); if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >= instance->fw_supported_vd_count) || (!fusion->fast_path_io)) { - io_request->RaidContext.raid_context.regLockFlags = 0; + io_request->RaidContext.raid_context.reg_lock_flags = 0; fp_possible = 0; } else { if (MR_BuildRaidContext(instance, &io_info, @@ -1945,6 +1949,8 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, fp_possible = false; } + praid_context = &io_request->RaidContext; + if (fp_possible) { megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp, local_map_ptr, start_lba_lo); @@ -1953,18 +1959,25 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (fusion->adapter_type == INVADER_SERIES) { - if (io_request->RaidContext.raid_context.regLockFlags == + if (io_request->RaidContext.raid_context.reg_lock_flags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - io_request->RaidContext.raid_context.Type + io_request->RaidContext.raid_context.type = MPI2_TYPE_CUDA; io_request->RaidContext.raid_context.nseg = 0x1; io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); - io_request->RaidContext.raid_context.regLockFlags |= + io_request->RaidContext.raid_context.reg_lock_flags |= (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | MR_RL_FLAGS_SEQ_NUM_ENABLE); + } else if (instance->is_ventura) { + io_request->RaidContext.raid_context_g35.type + = MPI2_TYPE_CUDA; + io_request->RaidContext.raid_context_g35.nseg = 0x1; + io_request->RaidContext.raid_context_g35.routing_flags.bits.sqn = 1; + io_request->IoFlags |= + cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); } if ((fusion->load_balance_info[device_id].loadBalanceFlag) && (io_info.isRead)) { @@ -1974,6 +1987,13 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, &io_info); scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG; cmd->pd_r1_lb = io_info.pd_after_lb; + if (instance->is_ventura) + io_request->RaidContext.raid_context_g35.span_arm + = io_info.span_arm; + else + io_request->RaidContext.raid_context.span_arm + = io_info.span_arm; + } else scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; @@ -1992,28 +2012,98 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, io_request->DevHandle = io_info.devHandle; /* populate the LUN field */ memcpy(io_request->LUN, raidLUN, 8); + if (instance->is_ventura) { + if (io_info.isRead) { + if ((raid->cpuAffinity.pdRead.cpu0) && + (raid->cpuAffinity.pdRead.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.pdRead.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } else { + if ((raid->cpuAffinity.pdWrite.cpu0) + && (raid->cpuAffinity.pdWrite.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.pdWrite.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + if (praid_context->raid_context_g35.routing_flags.bits.sld) { + praid_context->raid_context_g35.raid_flags + = (MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS + << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); + } + } + } } else { - io_request->RaidContext.raid_context.timeoutValue = + io_request->RaidContext.raid_context.timeout_value = cpu_to_le16(local_map_ptr->raidMap.fpPdIoTimeoutSec); cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (fusion->adapter_type == INVADER_SERIES) { if (io_info.do_fp_rlbypass || - (io_request->RaidContext.raid_context.regLockFlags + (io_request->RaidContext.raid_context.reg_lock_flags == REGION_TYPE_UNUSED)) cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - io_request->RaidContext.raid_context.Type + io_request->RaidContext.raid_context.type = MPI2_TYPE_CUDA; - io_request->RaidContext.raid_context.regLockFlags |= + io_request->RaidContext.raid_context.reg_lock_flags |= (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | MR_RL_FLAGS_SEQ_NUM_ENABLE); io_request->RaidContext.raid_context.nseg = 0x1; + } else if (instance->is_ventura) { + io_request->RaidContext.raid_context_g35.type + = MPI2_TYPE_CUDA; + io_request->RaidContext.raid_context_g35.routing_flags.bits.sqn = 1; + io_request->RaidContext.raid_context_g35.nseg = 0x1; } io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; io_request->DevHandle = cpu_to_le16(device_id); + + if (instance->is_ventura) { + if (io_info.isRead) { + if ((raid->cpuAffinity.ldRead.cpu0) + && (raid->cpuAffinity.ldRead.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.ldRead.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } else { + if ((raid->cpuAffinity.ldWrite.cpu0) && + (raid->cpuAffinity.ldWrite.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.ldWrite.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + + if (io_request->RaidContext.raid_context_g35.stream_detected + && (raid->level == 5) && + (raid->writeMode == MR_RL_WRITE_THROUGH_MODE)) { + if (praid_context->raid_context_g35.routing_flags.bits.cpu_sel + == MR_RAID_CTX_CPUSEL_FCFS) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } + } + } } /* Not FP */ } @@ -2048,9 +2138,9 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance, /* get RAID_Context pointer */ pRAID_Context = &io_request->RaidContext.raid_context; /* Check with FW team */ - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); - pRAID_Context->regLockRowLBA = 0; - pRAID_Context->regLockLength = 0; + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); + pRAID_Context->reg_lock_row_lba = 0; + pRAID_Context->reg_lock_length = 0; if (fusion->fast_path_io && ( device_id < instance->fw_supported_vd_count)) { @@ -2069,7 +2159,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance, io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; io_request->DevHandle = cpu_to_le16(device_id); io_request->LUN[1] = scmd->device->lun; - pRAID_Context->timeoutValue = + pRAID_Context->timeout_value = cpu_to_le16 (scmd->request->timeout / HZ); cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << @@ -2077,9 +2167,11 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance, } else { /* set RAID context values */ - pRAID_Context->configSeqNum = raid->seqNum; - pRAID_Context->regLockFlags = REGION_TYPE_SHARED_READ; - pRAID_Context->timeoutValue = cpu_to_le16(raid->fpIoTimeoutForLd); + pRAID_Context->config_seq_num = raid->seqNum; + if (!instance->is_ventura) + pRAID_Context->reg_lock_flags = REGION_TYPE_SHARED_READ; + pRAID_Context->timeout_value = + cpu_to_le16(raid->fpIoTimeoutForLd); /* get the DevHandle for the PD (since this is fpNonRWCapable, this is a single disk RAID0) */ @@ -2134,12 +2226,12 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, io_request = cmd->io_request; /* get RAID_Context pointer */ pRAID_Context = &io_request->RaidContext.raid_context; - pRAID_Context->regLockFlags = 0; - pRAID_Context->regLockRowLBA = 0; - pRAID_Context->regLockLength = 0; + pRAID_Context->reg_lock_flags = 0; + pRAID_Context->reg_lock_row_lba = 0; + pRAID_Context->reg_lock_length = 0; io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); io_request->LUN[1] = scmd->device->lun; - pRAID_Context->RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD + pRAID_Context->raid_flags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; /* If FW supports PD sequence number */ @@ -2148,24 +2240,27 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, /* TgtId must be incremented by 255 as jbod seq number is index * below raid map */ - pRAID_Context->VirtualDiskTgtId = + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1)); - pRAID_Context->configSeqNum = pd_sync->seq[pd_index].seqNum; + pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum; io_request->DevHandle = pd_sync->seq[pd_index].devHandle; - pRAID_Context->regLockFlags |= + if (instance->is_ventura) + io_request->RaidContext.raid_context_g35.routing_flags.bits.sqn = 1; + else + pRAID_Context->reg_lock_flags |= (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA); - pRAID_Context->Type = MPI2_TYPE_CUDA; + pRAID_Context->type = MPI2_TYPE_CUDA; pRAID_Context->nseg = 0x1; } else if (fusion->fast_path_io) { - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); - pRAID_Context->configSeqNum = 0; + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); + pRAID_Context->config_seq_num = 0; local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; io_request->DevHandle = local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; } else { /* Want to send all IO via FW path */ - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); - pRAID_Context->configSeqNum = 0; + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); + pRAID_Context->config_seq_num = 0; io_request->DevHandle = cpu_to_le16(0xFFFF); } @@ -2181,14 +2276,14 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value); - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); + pRAID_Context->timeout_value = cpu_to_le16(os_timeout_value); + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); } else { /* system pd Fast Path */ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; timeout_limit = (scmd->device->type == TYPE_DISK) ? 255 : 0xFFFF; - pRAID_Context->timeoutValue = + pRAID_Context->timeout_value = cpu_to_le16((os_timeout_value > timeout_limit) ? timeout_limit : os_timeout_value); if (fusion->adapter_type == INVADER_SERIES) @@ -2227,8 +2322,8 @@ megasas_build_io_fusion(struct megasas_instance *instance, io_request->Control = 0; io_request->EEDPBlockSize = 0; io_request->ChainOffset = 0; - io_request->RaidContext.raid_context.RAIDFlags = 0; - io_request->RaidContext.raid_context.Type = 0; + io_request->RaidContext.raid_context.raid_flags = 0; + io_request->RaidContext.raid_context.type = 0; io_request->RaidContext.raid_context.nseg = 0; memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len); @@ -2273,11 +2368,16 @@ megasas_build_io_fusion(struct megasas_instance *instance, return 1; } - /* numSGE store lower 8 bit of sge_count. - * numSGEExt store higher 8 bit of sge_count - */ - io_request->RaidContext.raid_context.numSGE = sge_count; - io_request->RaidContext.raid_context.numSGEExt = (u8)(sge_count >> 8); + if (instance->is_ventura) + io_request->RaidContext.raid_context_g35.num_sge = sge_count; + else { + /* numSGE store lower 8 bit of sge_count. + * numSGEExt store higher 8 bit of sge_count + */ + io_request->RaidContext.raid_context.num_sge = sge_count; + io_request->RaidContext.raid_context.num_sge_ext = + (u8)(sge_count >> 8); + } io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING); @@ -2326,6 +2426,10 @@ void megasas_fpio_to_ldio(struct megasas_instance *instance, struct megasas_cmd_fusion *cmd, struct scsi_cmnd *scmd) { struct fusion_context *fusion; + union RAID_CONTEXT_UNION *praid_context; + struct MR_LD_RAID *raid; + struct MR_DRV_RAID_MAP_ALL *local_map_ptr; + u32 device_id, ld; fusion = instance->ctrl_context; cmd->request_desc->SCSIIO.RequestFlags = @@ -2349,6 +2453,35 @@ void megasas_fpio_to_ldio(struct megasas_instance *instance, cmd->io_request->Control = 0; cmd->io_request->EEDPBlockSize = 0; cmd->is_raid_1_fp_write = 0; + + device_id = MEGASAS_DEV_INDEX(cmd->scmd); + local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; + ld = MR_TargetIdToLdGet(device_id, local_map_ptr); + raid = MR_LdRaidGet(ld, local_map_ptr); + praid_context = &cmd->io_request->RaidContext; + if (cmd->scmd->sc_data_direction == PCI_DMA_FROMDEVICE) { + if ((raid->cpuAffinity.ldRead.cpu0) + && (raid->cpuAffinity.ldRead.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.ldRead.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } else { + if ((raid->cpuAffinity.ldWrite.cpu0) + && (raid->cpuAffinity.ldWrite.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.ldWrite.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } } /* megasas_prepate_secondRaid1_IO @@ -2585,7 +2718,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) scmd_local = cmd_fusion->scmd; status = scsi_io_req->RaidContext.raid_context.status; - extStatus = scsi_io_req->RaidContext.raid_context.exStatus; + extStatus = scsi_io_req->RaidContext.raid_context.ex_status; sense = cmd_fusion->sense; data_length = scsi_io_req->DataLength; @@ -2653,13 +2786,13 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) status = r1_cmd->io_request->RaidContext.raid_context.status; extStatus = - r1_cmd->io_request->RaidContext.raid_context.exStatus; + r1_cmd->io_request->RaidContext.raid_context.ex_status; data_length = r1_cmd->io_request->DataLength; sense = r1_cmd->sense; } r1_cmd->io_request->RaidContext.raid_context.status = 0; - r1_cmd->io_request->RaidContext.raid_context.exStatus = 0; + r1_cmd->io_request->RaidContext.raid_context.ex_status = 0; cmd_fusion->is_raid_1_fp_write = 0; r1_cmd->is_raid_1_fp_write = 0; r1_cmd->cmd_completed = false; @@ -2669,10 +2802,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) if (!cmd_fusion->is_raid_1_fp_write) { map_cmd_status(fusion, scmd_local, status, extStatus, data_length, sense); - scsi_io_req->RaidContext.raid_context.status - = 0; - scsi_io_req->RaidContext.raid_context.exStatus - = 0; + scsi_io_req->RaidContext.raid_context.status = 0; + scsi_io_req->RaidContext.raid_context.ex_status = 0; megasas_return_cmd_fusion(instance, cmd_fusion); scsi_dma_unmap(scmd_local); scmd_local->scsi_done(scmd_local); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 3a5af3bb9989..4adb0d490af0 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -59,6 +59,8 @@ #define MR_RL_FLAGS_GRANT_DESTINATION_CPU1 0x10 #define MR_RL_FLAGS_GRANT_DESTINATION_CUDA 0x80 #define MR_RL_FLAGS_SEQ_NUM_ENABLE 0x8 +#define MR_RL_WRITE_THROUGH_MODE 0x00 +#define MR_RL_WRITE_BACK_MODE 0x01 /* T10 PI defines */ #define MR_PROT_INFO_TYPE_CONTROLLER 0x8 @@ -81,6 +83,11 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0, MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1, + MR_RAID_FLAGS_IO_SUB_TYPE_RMW_DATA = 2, + MR_RAID_FLAGS_IO_SUB_TYPE_RMW_P = 3, + MR_RAID_FLAGS_IO_SUB_TYPE_RMW_Q = 4, + MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS = 6, + MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7 }; /* @@ -109,29 +116,29 @@ enum MR_FUSION_ADAPTER_TYPE { struct RAID_CONTEXT { #if defined(__BIG_ENDIAN_BITFIELD) - u8 nseg:4; - u8 Type:4; + u8 nseg:4; + u8 type:4; #else - u8 Type:4; - u8 nseg:4; + u8 type:4; + u8 nseg:4; #endif - u8 resvd0; - __le16 timeoutValue; - u8 regLockFlags; - u8 resvd1; - __le16 VirtualDiskTgtId; - __le64 regLockRowLBA; - __le32 regLockLength; - __le16 nextLMId; - u8 exStatus; - u8 status; - u8 RAIDFlags; - u8 numSGE; - __le16 configSeqNum; - u8 spanArm; - u8 priority; - u8 numSGEExt; - u8 resvd2; + u8 resvd0; + __le16 timeout_value; + u8 reg_lock_flags; + u8 resvd1; + __le16 virtual_disk_tgt_id; + __le64 reg_lock_row_lba; + __le32 reg_lock_length; + __le16 next_lmid; + u8 ex_status; + u8 status; + u8 raid_flags; + u8 num_sge; + __le16 config_seq_num; + u8 span_arm; + u8 priority; + u8 num_sge_ext; + u8 resvd2; }; /* @@ -187,7 +194,7 @@ struct RAID_CONTEXT_G35 { } smid; u8 ex_status; /* 0x16 : OUT */ u8 status; /* 0x17 status */ - u8 RAIDFlags; /* 0x18 resvd[7:6], ioSubType[5:4], + u8 raid_flags; /* 0x18 resvd[7:6], ioSubType[5:4], * resvd[3:1], preferredCpu[0] */ u8 span_arm; /* 0x1C span[7:5], arm[4:0] */ @@ -672,14 +679,17 @@ struct MPI2_IOC_INIT_REQUEST { #define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE) #define MAX_LOGICAL_DRIVES 64 #define MAX_LOGICAL_DRIVES_EXT 256 +#define MAX_LOGICAL_DRIVES_DYN 512 #define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES) #define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES) #define MAX_ARRAYS 128 #define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS) #define MAX_ARRAYS_EXT 256 #define MAX_API_ARRAYS_EXT (MAX_ARRAYS_EXT) +#define MAX_API_ARRAYS_DYN 512 #define MAX_PHYSICAL_DEVICES 256 #define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) +#define MAX_RAIDMAP_PHYSICAL_DEVICES_DYN 512 #define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 #define MR_DCMD_SYSTEM_PD_MAP_GET_INFO 0x0200e102 #define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/ @@ -726,12 +736,56 @@ struct MR_SPAN_BLOCK_INFO { struct MR_SPAN_INFO block_span_info; }; +#define MR_RAID_CTX_CPUSEL_0 0 +#define MR_RAID_CTX_CPUSEL_1 1 +#define MR_RAID_CTX_CPUSEL_2 2 +#define MR_RAID_CTX_CPUSEL_3 3 +#define MR_RAID_CTX_CPUSEL_FCFS 0xF + +struct MR_CPU_AFFINITY_MASK { + union { + struct { +#ifndef MFI_BIG_ENDIAN + u8 hw_path:1; + u8 cpu0:1; + u8 cpu1:1; + u8 cpu2:1; + u8 cpu3:1; + u8 reserved:3; +#else + u8 reserved:3; + u8 cpu3:1; + u8 cpu2:1; + u8 cpu1:1; + u8 cpu0:1; + u8 hw_path:1; +#endif + }; + u8 core_mask; + }; +}; + +struct MR_IO_AFFINITY { + union { + struct { + struct MR_CPU_AFFINITY_MASK pdRead; + struct MR_CPU_AFFINITY_MASK pdWrite; + struct MR_CPU_AFFINITY_MASK ldRead; + struct MR_CPU_AFFINITY_MASK ldWrite; + }; + u32 word; + }; + u8 maxCores; /* Total cores + HW Path in ROC */ + u8 reserved[3]; +}; + struct MR_LD_RAID { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved4:3; - u32 fp_cache_bypass_capable:1; - u32 fp_rmw_capable:1; + u32 reserved4:2; + u32 fp_cache_bypass_capable:1; + u32 fp_rmw_capable:1; + u32 disable_coalescing:1; u32 fpBypassRegionLock:1; u32 tmCapable:1; u32 fpNonRWCapable:1; @@ -759,9 +813,10 @@ struct MR_LD_RAID { u32 fpNonRWCapable:1; u32 tmCapable:1; u32 fpBypassRegionLock:1; - u32 fp_rmw_capable:1; - u32 fp_cache_bypass_capable:1; - u32 reserved4:3; + u32 disable_coalescing:1; + u32 fp_rmw_capable:1; + u32 fp_cache_bypass_capable:1; + u32 reserved4:2; #endif } capability; __le32 reserved6; @@ -788,7 +843,36 @@ struct MR_LD_RAID { u8 LUN[8]; /* 0x24 8 byte LUN field used for SCSI IO's */ u8 fpIoTimeoutForLd;/*0x2C timeout value used by driver in FP IO*/ - u8 reserved3[0x80-0x2D]; /* 0x2D */ + /* Ox2D This LD accept priority boost of this type */ + u8 ld_accept_priority_type; + u8 reserved2[2]; /* 0x2E - 0x2F */ + /* 0x30 - 0x33, Logical block size for the LD */ + u32 logical_block_length; + struct { +#ifndef MFI_BIG_ENDIAN + /* 0x34, P_I_EXPONENT from READ CAPACITY 16 */ + u32 ld_pi_exp:4; + /* 0x34, LOGICAL BLOCKS PER PHYSICAL + * BLOCK EXPONENT from READ CAPACITY 16 + */ + u32 ld_logical_block_exp:4; + u32 reserved1:24; /* 0x34 */ +#else + u32 reserved1:24; /* 0x34 */ + /* 0x34, LOGICAL BLOCKS PER PHYSICAL + * BLOCK EXPONENT from READ CAPACITY 16 + */ + u32 ld_logical_block_exp:4; + /* 0x34, P_I_EXPONENT from READ CAPACITY 16 */ + u32 ld_pi_exp:4; +#endif + }; /* 0x34 - 0x37 */ + /* 0x38 - 0x3f, This will determine which + * core will process LD IO and PD IO. + */ + struct MR_IO_AFFINITY cpuAffinity; + /* Bit definiations are specified by MR_IO_AFFINITY */ + u8 reserved3[0x80-0x40]; /* 0x40 - 0x7f */ }; struct MR_LD_SPAN_MAP { @@ -846,6 +930,91 @@ struct MR_LD_TARGET_SYNC { __le16 seqNum; }; +/* + * RAID Map descriptor Types. + * Each element should uniquely idetify one data structure in the RAID map + */ +enum MR_RAID_MAP_DESC_TYPE { + /* MR_DEV_HANDLE_INFO data */ + RAID_MAP_DESC_TYPE_DEVHDL_INFO = 0x0, + /* target to Ld num Index map */ + RAID_MAP_DESC_TYPE_TGTID_INFO = 0x1, + /* MR_ARRAY_INFO data */ + RAID_MAP_DESC_TYPE_ARRAY_INFO = 0x2, + /* MR_LD_SPAN_MAP data */ + RAID_MAP_DESC_TYPE_SPAN_INFO = 0x3, + RAID_MAP_DESC_TYPE_COUNT, +}; + +/* + * This table defines the offset, size and num elements of each descriptor + * type in the RAID Map buffer + */ +struct MR_RAID_MAP_DESC_TABLE { + /* Raid map descriptor type */ + u32 raid_map_desc_type; + /* Offset into the RAID map buffer where + * descriptor data is saved + */ + u32 raid_map_desc_offset; + /* total size of the + * descriptor buffer + */ + u32 raid_map_desc_buffer_size; + /* Number of elements contained in the + * descriptor buffer + */ + u32 raid_map_desc_elements; +}; + +/* + * Dynamic Raid Map Structure. + */ +struct MR_FW_RAID_MAP_DYNAMIC { + u32 raid_map_size; /* total size of RAID Map structure */ + u32 desc_table_offset;/* Offset of desc table into RAID map*/ + u32 desc_table_size; /* Total Size of desc table */ + /* Total Number of elements in the desc table */ + u32 desc_table_num_elements; + u64 reserved1; + u32 reserved2[3]; /*future use */ + /* timeout value used by driver in FP IOs */ + u8 fp_pd_io_timeout_sec; + u8 reserved3[3]; + /* when this seqNum increments, driver needs to + * release RMW buffers asap + */ + u32 rmw_fp_seq_num; + u16 ld_count; /* count of lds. */ + u16 ar_count; /* count of arrays */ + u16 span_count; /* count of spans */ + u16 reserved4[3]; +/* + * The below structure of pointers is only to be used by the driver. + * This is added in the ,API to reduce the amount of code changes + * needed in the driver to support dynamic RAID map Firmware should + * not update these pointers while preparing the raid map + */ + union { + struct { + struct MR_DEV_HANDLE_INFO *dev_hndl_info; + u16 *ld_tgt_id_to_ld; + struct MR_ARRAY_INFO *ar_map_info; + struct MR_LD_SPAN_MAP *ld_span_map; + }; + u64 ptr_structure_size[RAID_MAP_DESC_TYPE_COUNT]; + }; +/* + * RAID Map descriptor table defines the layout of data in the RAID Map. + * The size of the descriptor table itself could change. + */ + /* Variable Size descriptor Table. */ + struct MR_RAID_MAP_DESC_TABLE + raid_map_desc_table[RAID_MAP_DESC_TYPE_COUNT]; + /* Variable Size buffer containing all data */ + u32 raid_map_desc_data[1]; +}; /* Dynamicaly sized RAID MAp structure */ + #define IEEE_SGE_FLAGS_ADDR_MASK (0x03) #define IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) #define IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) @@ -955,9 +1124,10 @@ struct MR_DRV_RAID_MAP { __le16 spanCount; __le16 reserve3; - struct MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES]; - u8 ldTgtIdToLd[MAX_LOGICAL_DRIVES_EXT]; - struct MR_ARRAY_INFO arMapInfo[MAX_API_ARRAYS_EXT]; + struct MR_DEV_HANDLE_INFO + devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES_DYN]; + u16 ldTgtIdToLd[MAX_LOGICAL_DRIVES_DYN]; + struct MR_ARRAY_INFO arMapInfo[MAX_API_ARRAYS_DYN]; struct MR_LD_SPAN_MAP ldSpanMap[1]; }; @@ -969,7 +1139,7 @@ struct MR_DRV_RAID_MAP { struct MR_DRV_RAID_MAP_ALL { struct MR_DRV_RAID_MAP raidMap; - struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_EXT - 1]; + struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_DYN - 1]; } __packed; @@ -1088,7 +1258,7 @@ struct fusion_context { u8 chain_offset_io_request; u8 chain_offset_mfi_pthru; - struct MR_FW_RAID_MAP_ALL *ld_map[2]; + struct MR_FW_RAID_MAP_DYNAMIC *ld_map[2]; dma_addr_t ld_map_phys[2]; /*Non dma-able memory. Driver local copy.*/ @@ -1096,6 +1266,8 @@ struct fusion_context { u32 max_map_sz; u32 current_map_sz; + u32 old_map_sz; + u32 new_map_sz; u32 drv_map_sz; u32 drv_map_pages; struct MR_PD_CFG_SEQ_NUM_SYNC *pd_seq_sync[JBOD_MAPS_COUNT]; From 9581ebebbe351d99579e8701e238c2771ccdae93 Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:49 -0500 Subject: [PATCH 0339/1587] scsi: megaraid_sas: Add the Support for SAS3.5 Generic Megaraid Controllers Capabilities The Megaraid driver has to support the SAS3.5 Generic Megaraid Controllers Firmware functionality. Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 53 ++++++++++----------- drivers/scsi/megaraid/megaraid_sas_fusion.c | 19 ++++---- drivers/scsi/megaraid/megaraid_sas_fusion.h | 1 + 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index fd6ddde43d03..19bc3501f28f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5042,34 +5042,29 @@ static int megasas_init_fw(struct megasas_instance *instance) reg_set = instance->reg_set; - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_PLASMA: - case PCI_DEVICE_ID_LSI_INVADER: - case PCI_DEVICE_ID_LSI_FURY: - case PCI_DEVICE_ID_LSI_INTRUDER: - case PCI_DEVICE_ID_LSI_INTRUDER_24: - case PCI_DEVICE_ID_LSI_CUTLASS_52: - case PCI_DEVICE_ID_LSI_CUTLASS_53: + if (fusion) instance->instancet = &megasas_instance_template_fusion; - break; - case PCI_DEVICE_ID_LSI_SAS1078R: - case PCI_DEVICE_ID_LSI_SAS1078DE: - instance->instancet = &megasas_instance_template_ppc; - break; - case PCI_DEVICE_ID_LSI_SAS1078GEN2: - case PCI_DEVICE_ID_LSI_SAS0079GEN2: - instance->instancet = &megasas_instance_template_gen2; - break; - case PCI_DEVICE_ID_LSI_SAS0073SKINNY: - case PCI_DEVICE_ID_LSI_SAS0071SKINNY: - instance->instancet = &megasas_instance_template_skinny; - break; - case PCI_DEVICE_ID_LSI_SAS1064R: - case PCI_DEVICE_ID_DELL_PERC5: - default: - instance->instancet = &megasas_instance_template_xscale; - break; + else { + switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_SAS1078R: + case PCI_DEVICE_ID_LSI_SAS1078DE: + instance->instancet = &megasas_instance_template_ppc; + break; + case PCI_DEVICE_ID_LSI_SAS1078GEN2: + case PCI_DEVICE_ID_LSI_SAS0079GEN2: + instance->instancet = &megasas_instance_template_gen2; + break; + case PCI_DEVICE_ID_LSI_SAS0073SKINNY: + case PCI_DEVICE_ID_LSI_SAS0071SKINNY: + instance->instancet = &megasas_instance_template_skinny; + break; + case PCI_DEVICE_ID_LSI_SAS1064R: + case PCI_DEVICE_ID_DELL_PERC5: + default: + instance->instancet = &megasas_instance_template_xscale; + instance->pd_list_not_supported = 1; + break; + } } if (megasas_transition_to_ready(instance, 0)) { @@ -5819,7 +5814,9 @@ static int megasas_probe_one(struct pci_dev *pdev, if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) fusion->adapter_type = THUNDERBOLT_SERIES; - else if (!instance->is_ventura) + else if (instance->is_ventura) + fusion->adapter_type = VENTURA_SERIES; + else fusion->adapter_type = INVADER_SERIES; } break; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 29e883fa3ead..ac424ba59ceb 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -244,7 +244,10 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c reg_set = instance->reg_set; - cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF; + /* ventura FW does not fill outbound_scratch_pad_3 with queue depth */ + if (!instance->is_ventura) + cur_max_fw_cmds = + readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF; if (dual_qdepth_disable || !cur_max_fw_cmds) cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; @@ -837,7 +840,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations); /* driver support Extended MSIX */ - if (fusion->adapter_type == INVADER_SERIES) + if (fusion->adapter_type >= INVADER_SERIES) drv_ops->mfi_capabilities.support_additional_msix = 1; /* driver supports HA / Remote LUN over Fast Path interface */ drv_ops->mfi_capabilities.support_fp_remote_lun = 1; @@ -1491,7 +1494,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, fusion = instance->ctrl_context; - if (fusion->adapter_type == INVADER_SERIES) { + if (fusion->adapter_type >= INVADER_SERIES) { struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr; sgl_ptr_end += fusion->max_sge_in_main_msg - 1; sgl_ptr_end->Flags = 0; @@ -1508,7 +1511,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl)); sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl)); sgl_ptr->Flags = 0; - if (fusion->adapter_type == INVADER_SERIES) + if (fusion->adapter_type >= INVADER_SERIES) if (i == sge_count - 1) sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; sgl_ptr++; @@ -1519,7 +1522,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, (sge_count > fusion->max_sge_in_main_msg)) { struct MPI25_IEEE_SGE_CHAIN64 *sg_chain; - if (fusion->adapter_type == INVADER_SERIES) { + if (fusion->adapter_type >= INVADER_SERIES) { if ((le16_to_cpu(cmd->io_request->IoFlags) & MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) != MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) @@ -1535,7 +1538,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sg_chain = sgl_ptr; /* Prepare chain element */ sg_chain->NextChainOffset = 0; - if (fusion->adapter_type == INVADER_SERIES) + if (fusion->adapter_type >= INVADER_SERIES) sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT; else sg_chain->Flags = @@ -2286,7 +2289,7 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, pRAID_Context->timeout_value = cpu_to_le16((os_timeout_value > timeout_limit) ? timeout_limit : os_timeout_value); - if (fusion->adapter_type == INVADER_SERIES) + if (fusion->adapter_type >= INVADER_SERIES) io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); @@ -2998,7 +3001,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance, io_req = cmd->io_request; - if (fusion->adapter_type == INVADER_SERIES) { + if (fusion->adapter_type >= INVADER_SERIES) { struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL; sgl_ptr_end += fusion->max_sge_in_main_msg - 1; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 4adb0d490af0..a9bc9c0a1cb9 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -107,6 +107,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { enum MR_FUSION_ADAPTER_TYPE { THUNDERBOLT_SERIES = 0, INVADER_SERIES = 1, + VENTURA_SERIES = 2, }; /* From 3e5eadb1a881bea2e3fa41f5ae7cdbfa36222d37 Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:50 -0500 Subject: [PATCH 0340/1587] scsi: megaraid_sas: Enable or Disable Fast path based on the PCI Threshold Bandwidth Large SEQ IO workload should sent as non fast path commands Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 8 ++++ drivers/scsi/megaraid/megaraid_sas_base.c | 48 +++++++++++++++++++++ drivers/scsi/megaraid/megaraid_sas_fp.c | 7 +++ drivers/scsi/megaraid/megaraid_sas_fusion.c | 16 ++++--- drivers/scsi/megaraid/megaraid_sas_fusion.h | 2 +- 5 files changed, 74 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 6ddf994a25b7..0696903e28fd 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1429,6 +1429,8 @@ enum FW_BOOT_CONTEXT { #define MFI_1068_FW_HANDSHAKE_OFFSET 0x64 #define MFI_1068_FW_READY 0xDDDD0000 +#define MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL HZ + #define MR_MAX_REPLY_QUEUES_OFFSET 0X0000001F #define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14 @@ -2101,6 +2103,10 @@ struct megasas_instance { atomic_t ldio_outstanding; atomic_t fw_reset_no_pci_access; + atomic64_t bytes_wrote; /* used for raid1 fast path enable or disable */ + atomic_t r1_write_fp_capable; + + struct megasas_instance_template *instancet; struct tasklet_struct isr_tasklet; struct work_struct work_init; @@ -2142,6 +2148,7 @@ struct megasas_instance { long reset_flags; struct mutex reset_mutex; struct timer_list sriov_heartbeat_timer; + struct timer_list r1_fp_hold_timer; char skip_heartbeat_timer_del; u8 requestorId; char PlasmaFW111; @@ -2158,6 +2165,7 @@ struct megasas_instance { bool is_ventura; bool msix_combined; u16 max_raid_mapsize; + u64 pci_threshold_bandwidth; /* used to control the fp writes */ }; struct MR_LD_VF_MAP { u32 size; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 19bc3501f28f..eba107898c7f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1940,6 +1940,9 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance) } /* Complete outstanding ioctls when adapter is killed */ megasas_complete_outstanding_ioctls(instance); + if (instance->is_ventura) + del_timer_sync(&instance->r1_fp_hold_timer); + } /** @@ -2438,6 +2441,24 @@ void megasas_sriov_heartbeat_handler(unsigned long instance_addr) } } +/*Handler for disabling/enabling raid 1 fast paths*/ +void megasas_change_r1_fp_status(unsigned long instance_addr) +{ + struct megasas_instance *instance = + (struct megasas_instance *)instance_addr; + if (atomic64_read(&instance->bytes_wrote) >= + instance->pci_threshold_bandwidth) { + + atomic64_set(&instance->bytes_wrote, 0); + atomic_set(&instance->r1_write_fp_capable, 0); + } else { + atomic64_set(&instance->bytes_wrote, 0); + atomic_set(&instance->r1_write_fp_capable, 1); + } + mod_timer(&instance->r1_fp_hold_timer, + jiffies + MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL); +} + /** * megasas_wait_for_outstanding - Wait for all outstanding cmds * @instance: Adapter soft state @@ -5362,6 +5383,17 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->skip_heartbeat_timer_del = 1; } + if (instance->is_ventura) { + atomic64_set(&instance->bytes_wrote, 0); + atomic_set(&instance->r1_write_fp_capable, 1); + megasas_start_timer(instance, + &instance->r1_fp_hold_timer, + megasas_change_r1_fp_status, + MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL); + dev_info(&instance->pdev->dev, "starting the raid 1 fp timer with interval %d\n", + MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL); + } + return 0; fail_get_ld_pd_list: @@ -6152,6 +6184,9 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) if (instance->requestorId && !instance->skip_heartbeat_timer_del) del_timer_sync(&instance->sriov_heartbeat_timer); + if (instance->is_ventura) + del_timer_sync(&instance->r1_fp_hold_timer); + megasas_flush_cache(instance); megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); @@ -6278,6 +6313,16 @@ megasas_resume(struct pci_dev *pdev) megasas_setup_jbod_map(instance); instance->unload = 0; + if (instance->is_ventura) { + atomic64_set(&instance->bytes_wrote, 0); + atomic_set(&instance->r1_write_fp_capable, 1); + megasas_start_timer(instance, + &instance->r1_fp_hold_timer, + megasas_change_r1_fp_status, + MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL); + } + + /* * Initiate AEN (Asynchronous Event Notification) */ @@ -6366,6 +6411,9 @@ static void megasas_detach_one(struct pci_dev *pdev) if (instance->requestorId && !instance->skip_heartbeat_timer_del) del_timer_sync(&instance->sriov_heartbeat_timer); + if (instance->is_ventura) + del_timer_sync(&instance->r1_fp_hold_timer); + if (instance->fw_crash_state != UNAVAILABLE) megasas_free_host_crash_buffer(instance); scsi_remove_host(instance->host); diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index f1384b01b3d3..322a72b593e3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -197,6 +197,9 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) if (instance->max_raid_mapsize) { fw_map_dyn = fusion->ld_map[(instance->map_id & 1)]; + if (fw_map_dyn->pci_threshold_bandwidth) + instance->pci_threshold_bandwidth = + le64_to_cpu(fw_map_dyn->pci_threshold_bandwidth); #if VD_EXT_DEBUG dev_dbg(&instance->pdev->dev, "raidMapSize 0x%x fw_map_dyn->descTableOffset 0x%x\n", le32_to_cpu(fw_map_dyn->raid_map_size), @@ -204,6 +207,8 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) dev_dbg(&instance->pdev->dev, "descTableSize 0x%x descTableNumElements 0x%x\n", le32_to_cpu(fw_map_dyn->desc_table_size), le32_to_cpu(fw_map_dyn->desc_table_num_elements)); + dev_dbg(&instance->pdev->dev, "PCIThreasholdBandwidth %llu\n", + instance->pci_threshold_bandwidth); dev_dbg(&instance->pdev->dev, "drv map %p ldCount %d\n", drv_map, fw_map_dyn->ld_count); #endif @@ -434,6 +439,8 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) sizeof(struct MR_DEV_HANDLE_INFO) * MAX_RAIDMAP_PHYSICAL_DEVICES); } + if (instance->is_ventura && !instance->pci_threshold_bandwidth) + instance->pci_threshold_bandwidth = ULLONG_MAX; } /* diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index ac424ba59ceb..4d655e456709 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -95,6 +95,7 @@ extern unsigned int resetwaittime; extern unsigned int dual_qdepth_disable; static void megasas_free_rdpq_fusion(struct megasas_instance *instance); static void megasas_free_reply_fusion(struct megasas_instance *instance); +void megasas_change_r1_fp_status(unsigned long instance_addr); @@ -2628,8 +2629,9 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, * to get new command */ if (cmd->is_raid_1_fp_write && - atomic_inc_return(&instance->fw_outstanding) > - (instance->host->can_queue)) { + (atomic_inc_return(&instance->fw_outstanding) > + (instance->host->can_queue) || + (!atomic_read(&instance->r1_write_fp_capable)))) { megasas_fpio_to_ldio(instance, cmd, cmd->scmd); atomic_dec(&instance->fw_outstanding); } else if (cmd->is_raid_1_fp_write) { @@ -2638,17 +2640,19 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, megasas_prepare_secondRaid1_IO(instance, cmd, r1_cmd); } - /* * Issue the command to the FW */ + if (scmd->sc_data_direction == PCI_DMA_TODEVICE && instance->is_ventura) + atomic64_add(scsi_bufflen(scmd), &instance->bytes_wrote); megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura); - if (r1_cmd) + if (r1_cmd) { + atomic64_add(scsi_bufflen(scmd), &instance->bytes_wrote); megasas_fire_cmd_fusion(instance, r1_cmd->request_desc, - instance->is_ventura); - + instance->is_ventura); + } return 0; } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index a9bc9c0a1cb9..391aae6e27a4 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -977,7 +977,7 @@ struct MR_FW_RAID_MAP_DYNAMIC { u32 desc_table_size; /* Total Size of desc table */ /* Total Number of elements in the desc table */ u32 desc_table_num_elements; - u64 reserved1; + u64 pci_threshold_bandwidth; u32 reserved2[3]; /*future use */ /* timeout value used by driver in FP IOs */ u8 fp_pd_io_timeout_sec; From b71b49c209facf8fec3778142ae5e45bb6ca4afc Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:51 -0500 Subject: [PATCH 0341/1587] scsi: megaraid_sas: ldio_outstanding variable is not decremented in completion path ldio outstanding variable needs to be decremented in io completion path for iMR dual queue depth Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 4d655e456709..705102f5b3a2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2580,7 +2580,6 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, if (atomic_inc_return(&instance->fw_outstanding) > instance->host->can_queue) { - dev_err(&instance->pdev->dev, "Throttle IOs beyond Controller queue depth\n"); atomic_dec(&instance->fw_outstanding); return SCSI_MLQUEUE_HOST_BUSY; } @@ -2811,6 +2810,9 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) extStatus, data_length, sense); scsi_io_req->RaidContext.raid_context.status = 0; scsi_io_req->RaidContext.raid_context.ex_status = 0; + if (instance->ldio_threshold + && megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) + atomic_dec(&instance->ldio_outstanding); megasas_return_cmd_fusion(instance, cmd_fusion); scsi_dma_unmap(scmd_local); scmd_local->scsi_done(scmd_local); @@ -3959,7 +3961,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) scmd_local->result = megasas_check_mpio_paths(instance, scmd_local); - if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) + if (instance->ldio_threshold && + megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) atomic_dec(&instance->ldio_outstanding); megasas_return_cmd_fusion(instance, cmd_fusion); scsi_dma_unmap(scmd_local); From ede7c3ce82dc4001bbab33dddebab8c089f309e0 Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:52 -0500 Subject: [PATCH 0342/1587] scsi: megaraid_sas: Implement the PD Map support for SAS3.5 Generic Megaraid Controllers Update Linux driver to use new pdTargetId field for JBOD target ID Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 105 +++++++++++++++----- drivers/scsi/megaraid/megaraid_sas_base.c | 3 + drivers/scsi/megaraid/megaraid_sas_fusion.c | 6 ++ drivers/scsi/megaraid/megaraid_sas_fusion.h | 3 +- 4 files changed, 89 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 0696903e28fd..21c48e1aa52d 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1317,7 +1317,55 @@ struct megasas_ctrl_info { #endif } adapterOperations3; - u8 pad[0x800-0x7EC]; + struct { +#if defined(__BIG_ENDIAN_BITFIELD) + u8 reserved:7; + /* Indicates whether the CPLD image is part of + * the package and stored in flash + */ + u8 cpld_in_flash:1; +#else + u8 cpld_in_flash:1; + u8 reserved:7; +#endif + u8 reserved1[3]; + /* Null terminated string. Has the version + * information if cpld_in_flash = FALSE + */ + u8 userCodeDefinition[12]; + } cpld; /* Valid only if upgradableCPLD is TRUE */ + + struct { + #if defined(__BIG_ENDIAN_BITFIELD) + u16 reserved:8; + u16 fw_swaps_bbu_vpd_info:1; + u16 support_pd_map_target_id:1; + u16 support_ses_ctrl_in_multipathcfg:1; + u16 image_upload_supported:1; + u16 support_encrypted_mfc:1; + u16 supported_enc_algo:1; + u16 support_ibutton_less:1; + u16 ctrl_info_ext_supported:1; + #else + + u16 ctrl_info_ext_supported:1; + u16 support_ibutton_less:1; + u16 supported_enc_algo:1; + u16 support_encrypted_mfc:1; + u16 image_upload_supported:1; + /* FW supports LUN based association and target port based */ + u16 support_ses_ctrl_in_multipathcfg:1; + /* association for the SES device connected in multipath mode */ + /* FW defines Jbod target Id within MR_PD_CFG_SEQ */ + u16 support_pd_map_target_id:1; + /* FW swaps relevant fields in MR_BBU_VPD_INFO_FIXED to + * provide the data in little endian order + */ + u16 fw_swaps_bbu_vpd_info:1; + u16 reserved:8; + #endif + } adapter_operations4; + u8 pad[0x800-0x7FE]; /* 0x7FE pad to 2K for expansion */ } __packed; /* @@ -1557,33 +1605,35 @@ union megasas_sgl_frame { typedef union _MFI_CAPABILITIES { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:20; - u32 support_qd_throttling:1; - u32 support_fp_rlbypass:1; - u32 support_vfid_in_ioframe:1; - u32 support_ext_io_size:1; - u32 support_ext_queue_depth:1; - u32 security_protocol_cmds_fw:1; - u32 support_core_affinity:1; - u32 support_ndrive_r1_lb:1; - u32 support_max_255lds:1; - u32 support_fastpath_wb:1; - u32 support_additional_msix:1; - u32 support_fp_remote_lun:1; + u32 reserved:19; + u32 support_pd_map_target_id:1; + u32 support_qd_throttling:1; + u32 support_fp_rlbypass:1; + u32 support_vfid_in_ioframe:1; + u32 support_ext_io_size:1; + u32 support_ext_queue_depth:1; + u32 security_protocol_cmds_fw:1; + u32 support_core_affinity:1; + u32 support_ndrive_r1_lb:1; + u32 support_max_255lds:1; + u32 support_fastpath_wb:1; + u32 support_additional_msix:1; + u32 support_fp_remote_lun:1; #else - u32 support_fp_remote_lun:1; - u32 support_additional_msix:1; - u32 support_fastpath_wb:1; - u32 support_max_255lds:1; - u32 support_ndrive_r1_lb:1; - u32 support_core_affinity:1; - u32 security_protocol_cmds_fw:1; - u32 support_ext_queue_depth:1; - u32 support_ext_io_size:1; - u32 support_vfid_in_ioframe:1; - u32 support_fp_rlbypass:1; - u32 support_qd_throttling:1; - u32 reserved:20; + u32 support_fp_remote_lun:1; + u32 support_additional_msix:1; + u32 support_fastpath_wb:1; + u32 support_max_255lds:1; + u32 support_ndrive_r1_lb:1; + u32 support_core_affinity:1; + u32 security_protocol_cmds_fw:1; + u32 support_ext_queue_depth:1; + u32 support_ext_io_size:1; + u32 support_vfid_in_ioframe:1; + u32 support_fp_rlbypass:1; + u32 support_qd_throttling:1; + u32 support_pd_map_target_id:1; + u32 reserved:19; #endif } mfi_capabilities; __le32 reg; @@ -2052,6 +2102,7 @@ struct megasas_instance { u32 crash_dump_drv_support; u32 crash_dump_app_support; u32 secure_jbod_support; + u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */ bool use_seqnum_jbod_fp; /* Added for PD sequence */ spinlock_t crashdump_lock; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index eba107898c7f..70891a76ca86 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4576,6 +4576,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance) le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties); le32_to_cpus((u32 *)&ctrl_info->adapterOperations2); le32_to_cpus((u32 *)&ctrl_info->adapterOperations3); + le16_to_cpus((u16 *)&ctrl_info->adapter_operations4); /* Update the latest Ext VD info. * From Init path, store current firmware details. @@ -4585,6 +4586,8 @@ megasas_get_ctrl_info(struct megasas_instance *instance) megasas_update_ext_vd_details(instance); instance->use_seqnum_jbod_fp = ctrl_info->adapterOperations3.useSeqNumJbodFP; + instance->support_morethan256jbod = + ctrl_info->adapter_operations4.support_pd_map_target_id; /*Check whether controller is iMR or MR */ instance->is_imr = (ctrl_info->memory_size ? 0 : 1); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 705102f5b3a2..9a9c84fb91b1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -858,6 +858,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) drv_ops->mfi_capabilities.support_ext_queue_depth = 1; drv_ops->mfi_capabilities.support_qd_throttling = 1; + drv_ops->mfi_capabilities.support_pd_map_target_id = 1; /* Convert capability to LE32 */ cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); @@ -2244,6 +2245,11 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, /* TgtId must be incremented by 255 as jbod seq number is index * below raid map */ + /* More than 256 PD/JBOD support for Ventura */ + if (instance->support_morethan256jbod) + pRAID_Context->virtual_disk_tgt_id = + pd_sync->seq[pd_index].pd_target_id; + else pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1)); pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 391aae6e27a4..3addd0cb2e99 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -1189,7 +1189,8 @@ struct MR_PD_CFG_SEQ { u8 reserved:7; #endif } capability; - u8 reserved[3]; + u8 reserved; + u16 pd_target_id; } __packed; struct MR_PD_CFG_SEQ_NUM_SYNC { From 223e4b93e61f7538681632bfb19edd4f27a0c319 Mon Sep 17 00:00:00 2001 From: Sasikumar Chandrasekaran Date: Tue, 10 Jan 2017 18:20:53 -0500 Subject: [PATCH 0343/1587] scsi: megaraid_sas: driver version upgrade Upgrade driver version. Signed-off-by: Sasikumar Chandrasekaran Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 21c48e1aa52d..ba9fbb71eb35 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -35,8 +35,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "06.812.07.00-rc1" -#define MEGASAS_RELDATE "August 22, 2016" +#define MEGASAS_VERSION "07.700.00.00-rc1" +#define MEGASAS_RELDATE "November 29, 2016" /* * Device IDs From f25c3aa9085e9625f3dcc20152dd780d01a54c5a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 10 Jan 2017 17:31:57 +0300 Subject: [PATCH 0344/1587] pinctrl: intel: Convert to use devm_gpiochip_add_data() This simplifies error handling and allows us to drop intel_pinctrl_remove() completely. Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-broxton.c | 1 - drivers/pinctrl/intel/pinctrl-intel.c | 23 ++++---------------- drivers/pinctrl/intel/pinctrl-intel.h | 2 -- drivers/pinctrl/intel/pinctrl-sunrisepoint.c | 1 - 4 files changed, 4 insertions(+), 23 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c index 59cb7a6fc5be..77e02faee411 100644 --- a/drivers/pinctrl/intel/pinctrl-broxton.c +++ b/drivers/pinctrl/intel/pinctrl-broxton.c @@ -1058,7 +1058,6 @@ static const struct dev_pm_ops bxt_pinctrl_pm_ops = { static struct platform_driver bxt_pinctrl_driver = { .probe = bxt_pinctrl_probe, - .remove = intel_pinctrl_remove, .driver = { .name = "broxton-pinctrl", .acpi_match_table = bxt_pinctrl_acpi_match, diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 1e139672f1af..447405809340 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -884,7 +884,7 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) pctrl->chip.base = -1; pctrl->irq = irq; - ret = gpiochip_add_data(&pctrl->chip, pctrl); + ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); if (ret) { dev_err(pctrl->dev, "failed to register gpiochip\n"); return ret; @@ -894,7 +894,7 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) 0, 0, pctrl->soc->npins); if (ret) { dev_err(pctrl->dev, "failed to add GPIO pin range\n"); - goto fail; + return ret; } /* @@ -907,24 +907,19 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) dev_name(pctrl->dev), pctrl); if (ret) { dev_err(pctrl->dev, "failed to request interrupt\n"); - goto fail; + return ret; } ret = gpiochip_irqchip_add(&pctrl->chip, &intel_gpio_irqchip, 0, handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_err(pctrl->dev, "failed to add irqchip\n"); - goto fail; + return ret; } gpiochip_set_chained_irqchip(&pctrl->chip, &intel_gpio_irqchip, irq, NULL); return 0; - -fail: - gpiochip_remove(&pctrl->chip); - - return ret; } static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) @@ -1046,16 +1041,6 @@ int intel_pinctrl_probe(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(intel_pinctrl_probe); -int intel_pinctrl_remove(struct platform_device *pdev) -{ - struct intel_pinctrl *pctrl = platform_get_drvdata(pdev); - - gpiochip_remove(&pctrl->chip); - - return 0; -} -EXPORT_SYMBOL_GPL(intel_pinctrl_remove); - #ifdef CONFIG_PM_SLEEP static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin) { diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h index b60215793017..c22c44485c5d 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.h +++ b/drivers/pinctrl/intel/pinctrl-intel.h @@ -121,8 +121,6 @@ struct intel_pinctrl_soc_data { int intel_pinctrl_probe(struct platform_device *pdev, const struct intel_pinctrl_soc_data *soc_data); -int intel_pinctrl_remove(struct platform_device *pdev); - #ifdef CONFIG_PM_SLEEP int intel_pinctrl_suspend(struct device *dev); int intel_pinctrl_resume(struct device *dev); diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c index c725a5313b4e..9877526c0807 100644 --- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c +++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c @@ -574,7 +574,6 @@ static const struct dev_pm_ops spt_pinctrl_pm_ops = { static struct platform_driver spt_pinctrl_driver = { .probe = spt_pinctrl_probe, - .remove = intel_pinctrl_remove, .driver = { .name = "sunrisepoint-pinctrl", .acpi_match_table = spt_pinctrl_acpi_match, From 0612413fbeedd4602e66e221bbe70dcd2b925ee8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Jan 2017 22:11:39 +0200 Subject: [PATCH 0345/1587] pinctrl: baytrail: Convert to use devm_*() This simplifies error handling and allows us to drop error path handlers completely. Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-baytrail.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 37300634b7d2..aedc3041c2ac 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1685,7 +1685,7 @@ static int byt_gpio_probe(struct byt_gpio *vg) vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio, sizeof(*vg->saved_context), GFP_KERNEL); #endif - ret = gpiochip_add_data(gc, vg); + ret = devm_gpiochip_add_data(&vg->pdev->dev, gc, vg); if (ret) { dev_err(&vg->pdev->dev, "failed adding byt-gpio chip\n"); return ret; @@ -1695,7 +1695,7 @@ static int byt_gpio_probe(struct byt_gpio *vg) 0, 0, vg->soc_data->npins); if (ret) { dev_err(&vg->pdev->dev, "failed to add GPIO pin range\n"); - goto fail; + return ret; } /* set up interrupts */ @@ -1706,7 +1706,7 @@ static int byt_gpio_probe(struct byt_gpio *vg) handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_err(&vg->pdev->dev, "failed to add irqchip\n"); - goto fail; + return ret; } gpiochip_set_chained_irqchip(gc, &byt_irqchip, @@ -1714,11 +1714,6 @@ static int byt_gpio_probe(struct byt_gpio *vg) byt_gpio_irq_handler); } - return ret; - -fail: - gpiochip_remove(&vg->chip); - return ret; } @@ -1802,7 +1797,7 @@ static int byt_pinctrl_probe(struct platform_device *pdev) vg->pctl_desc.pins = vg->soc_data->pins; vg->pctl_desc.npins = vg->soc_data->npins; - vg->pctl_dev = pinctrl_register(&vg->pctl_desc, &pdev->dev, vg); + vg->pctl_dev = devm_pinctrl_register(&pdev->dev, &vg->pctl_desc, vg); if (IS_ERR(vg->pctl_dev)) { dev_err(&pdev->dev, "failed to register pinctrl driver\n"); return PTR_ERR(vg->pctl_dev); @@ -1811,10 +1806,8 @@ static int byt_pinctrl_probe(struct platform_device *pdev) raw_spin_lock_init(&vg->lock); ret = byt_gpio_probe(vg); - if (ret) { - pinctrl_unregister(vg->pctl_dev); + if (ret) return ret; - } platform_set_drvdata(pdev, vg); pm_runtime_enable(&pdev->dev); From 476e3e1d0555a9170e050a9708f883814ce79354 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 5 Jan 2017 17:43:41 -0600 Subject: [PATCH 0346/1587] pinctrl: da850-pupd: Add to module device table This adds the pintrol-da850-pupd driver to the module device table so that udev will automatically bind the driver to the device. Signed-off-by: David Lechner Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-da850-pupd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/pinctrl-da850-pupd.c b/drivers/pinctrl/pinctrl-da850-pupd.c index b36a90a3f3e4..921729b4bb46 100644 --- a/drivers/pinctrl/pinctrl-da850-pupd.c +++ b/drivers/pinctrl/pinctrl-da850-pupd.c @@ -194,6 +194,7 @@ static const struct of_device_id da850_pupd_of_match[] = { { .compatible = "ti,da850-pupd" }, { } }; +MODULE_DEVICE_TABLE(of, da850_pupd_of_match); static struct platform_driver da850_pupd_driver = { .driver = { From 2104d12d11206b9477df13898c87aa19ad57a680 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 5 Jan 2017 08:07:55 -0800 Subject: [PATCH 0347/1587] pinctrl: Drop error prints on kzalloc() failure Upon failing kzalloc() will print an error message in the log, so there's no need for additional printouts. Also standardizes the "!ptr" vs "ptr == NULL" while I'm touching those lines. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 5b1ab06d92c2..65c0ae0969dc 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -237,10 +237,8 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev, } pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL); - if (pindesc == NULL) { - dev_err(pctldev->dev, "failed to alloc struct pin_desc\n"); + if (!pindesc) return -ENOMEM; - } /* Set owner */ pindesc->pctldev = pctldev; @@ -882,11 +880,8 @@ static struct pinctrl_state *create_state(struct pinctrl *p, struct pinctrl_state *state; state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) { - dev_err(p->dev, - "failed to alloc struct pinctrl_state\n"); + if (!state) return ERR_PTR(-ENOMEM); - } state->name = name; INIT_LIST_HEAD(&state->settings); @@ -913,11 +908,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev, return 0; setting = kzalloc(sizeof(*setting), GFP_KERNEL); - if (setting == NULL) { - dev_err(p->dev, - "failed to alloc struct pinctrl_setting\n"); + if (!setting) return -ENOMEM; - } setting->type = map->type; @@ -997,10 +989,8 @@ static struct pinctrl *create_pinctrl(struct device *dev, * a pin control handle with pinctrl_get() */ p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) { - dev_err(dev, "failed to alloc struct pinctrl\n"); + if (!p) return ERR_PTR(-ENOMEM); - } p->dev = dev; INIT_LIST_HEAD(&p->states); INIT_LIST_HEAD(&p->dt_maps); @@ -1357,10 +1347,8 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, } maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL); - if (!maps_node) { - pr_err("failed to alloc struct pinctrl_maps\n"); + if (!maps_node) return -ENOMEM; - } maps_node->num_maps = num_maps; if (dup) { @@ -1980,10 +1968,8 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, return ERR_PTR(-EINVAL); pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL); - if (pctldev == NULL) { - dev_err(dev, "failed to alloc struct pinctrl_dev\n"); + if (!pctldev) return ERR_PTR(-ENOMEM); - } /* Initialize pin control device struct */ pctldev->owner = pctldesc->owner; From 6e8b66c1b7aeb95cff643f358299cf1c5c630abb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 5 Jan 2017 22:55:43 -0200 Subject: [PATCH 0348/1587] pinctrl: imx7d-pinctrl: Fix a typo Fix a typo in "Peripherals". Signed-off-by: Fabio Estevam Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt index 457b2c68d47b..8c5d27c5b562 100644 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt @@ -19,7 +19,7 @@ iomuxc: iomuxc@30330000 { reg = <0x30330000 0x10000>; }; -Pheriparials using pads from iomuxc-lpsr support low state retention power +Peripherals using pads from iomuxc-lpsr support low state retention power state, under LPSR mode GPIO's state of pads are retain. Please refer to fsl,imx-pinctrl.txt in this directory for common binding part From 3775dac1bc385e8d7bfdbc68e8478e4b2bae1955 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 7 Jan 2017 09:32:15 +0300 Subject: [PATCH 0349/1587] pinctrl/amd: white space cleanups in amd_gpio_dbg_show() We accidentally deleted two tabs from the first line, but even with that fixed the conditions were not really kernel style. Put the && at the end of the line so we can align the condition clauses. Also add spaces around the "+" operator. Signed-off-by: Dan Carpenter Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-amd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index c2203699f1ab..1ee107f147d0 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -219,14 +219,14 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) { interrupt_enable = "interrupt is enabled|"; - if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF)) - && !(pin_reg & BIT(ACTIVE_LEVEL_OFF+1))) + if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF)) && + !(pin_reg & BIT(ACTIVE_LEVEL_OFF + 1))) active_level = "Active low|"; - else if (pin_reg & BIT(ACTIVE_LEVEL_OFF) - && !(pin_reg & BIT(ACTIVE_LEVEL_OFF+1))) + else if (pin_reg & BIT(ACTIVE_LEVEL_OFF) && + !(pin_reg & BIT(ACTIVE_LEVEL_OFF + 1))) active_level = "Active high|"; - else if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF)) - && pin_reg & BIT(ACTIVE_LEVEL_OFF+1)) + else if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF)) && + pin_reg & BIT(ACTIVE_LEVEL_OFF + 1)) active_level = "Active on both|"; else active_level = "Unknow Active level|"; From 56d9e4a76039afd504919cc5ec329fb0ce35812f Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 3 Jan 2017 23:16:27 +0800 Subject: [PATCH 0350/1587] pinctrl: sunxi: add driver for V3s SoC V3s SoC features only a pin controller (for the lack of CPUs part). Add a driver for this controller. Signed-off-by: Icenowy Zheng Acked-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/Kconfig | 4 + drivers/pinctrl/sunxi/Makefile | 1 + drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c | 321 ++++++++++++++++++++++ 3 files changed, 326 insertions(+) create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index c9f3434f6793..8ba10d830ce2 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -55,6 +55,10 @@ config PINCTRL_SUN8I_H3_R def_bool MACH_SUN8I select PINCTRL_SUNXI_COMMON +config PINCTRL_SUN8I_V3S + def_bool MACH_SUN8I + select PINCTRL_SUNXI + config PINCTRL_SUN9I_A80 def_bool MACH_SUN9I select PINCTRL_SUNXI diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index 4178408d3705..7bcb4683bce5 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -15,5 +15,6 @@ obj-$(CONFIG_PINCTRL_SUN50I_A64) += pinctrl-sun50i-a64.o obj-$(CONFIG_PINCTRL_SUN8I_A83T) += pinctrl-sun8i-a83t.o obj-$(CONFIG_PINCTRL_SUN8I_H3) += pinctrl-sun8i-h3.o obj-$(CONFIG_PINCTRL_SUN8I_H3_R) += pinctrl-sun8i-h3-r.o +obj-$(CONFIG_PINCTRL_SUN8I_V3S) += pinctrl-sun8i-v3s.o obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o obj-$(CONFIG_PINCTRL_SUN9I_A80_R) += pinctrl-sun9i-a80-r.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c new file mode 100644 index 000000000000..c86d3c42a905 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c @@ -0,0 +1,321 @@ +/* + * Allwinner V3s SoCs pinctrl driver. + * + * Copyright (C) 2016 Icenowy Zheng + * + * Based on pinctrl-sun8i-h3.c, which is: + * Copyright (C) 2015 Jens Kuske + * + * Based on pinctrl-sun8i-a23.c, which is: + * Copyright (C) 2014 Chen-Yu Tsai + * Copyright (C) 2014 Maxime Ripard + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-sunxi.h" + +static const struct sunxi_desc_pin sun8i_v3s_pins[] = { + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* PB_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* PB_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* PB_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* D1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* PB_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm0"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* PB_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm1"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* PB_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* PB_EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* PB_EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1"), /* SDA */ + SUNXI_FUNCTION(0x3, "uart0"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* PB_EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1"), /* SCK */ + SUNXI_FUNCTION(0x3, "uart0"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* PB_EINT9 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc2"), /* CLK */ + SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc2"), /* CMD */ + SUNXI_FUNCTION(0x3, "spi0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc2"), /* RST */ + SUNXI_FUNCTION(0x3, "spi0")), /* CS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc2"), /* D0 */ + SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* PCLK */ + SUNXI_FUNCTION(0x3, "lcd")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* MCLK */ + SUNXI_FUNCTION(0x3, "lcd")), /* DE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* HSYNC */ + SUNXI_FUNCTION(0x3, "lcd")), /* HSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* VSYNC */ + SUNXI_FUNCTION(0x3, "lcd")), /* VSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D0 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D1 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D2 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D3 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D4 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D5 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D6 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D7 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D8 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D9 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D10 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D11 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D12 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D18 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D13 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D19 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D14 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D20 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D15 */ + SUNXI_FUNCTION(0x3, "lcd")), /* D21 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 20), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* FIELD */ + SUNXI_FUNCTION(0x3, "csi_mipi")), /* MCLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 21), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* SCK */ + SUNXI_FUNCTION(0x3, "i2c1"), /* SCK */ + SUNXI_FUNCTION(0x4, "uart1")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 22), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* SDA */ + SUNXI_FUNCTION(0x3, "i2c1"), /* SDA */ + SUNXI_FUNCTION(0x4, "uart1")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 23), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "lcd"), /* D22 */ + SUNXI_FUNCTION(0x4, "uart1")), /* RTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 24), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "lcd"), /* D23 */ + SUNXI_FUNCTION(0x4, "uart1")), /* CTS */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ + SUNXI_FUNCTION(0x3, "jtag")), /* MS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ + SUNXI_FUNCTION(0x3, "jtag")), /* DI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ + SUNXI_FUNCTION(0x3, "uart0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ + SUNXI_FUNCTION(0x3, "jtag")), /* DO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ + SUNXI_FUNCTION(0x3, "uart0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ + SUNXI_FUNCTION(0x3, "jtag")), /* CK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)), /* PG_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)), /* PG_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)), /* PG_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)), /* PG_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)), /* PG_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)), /* PG_EINT5 */ +}; + +static const struct sunxi_pinctrl_desc sun8i_v3s_pinctrl_data = { + .pins = sun8i_v3s_pins, + .npins = ARRAY_SIZE(sun8i_v3s_pins), + .irq_banks = 2, + .irq_read_needs_mux = true +}; + +static int sun8i_v3s_pinctrl_probe(struct platform_device *pdev) +{ + return sunxi_pinctrl_init(pdev, + &sun8i_v3s_pinctrl_data); +} + +static const struct of_device_id sun8i_v3s_pinctrl_match[] = { + { .compatible = "allwinner,sun8i-v3s-pinctrl", }, + {} +}; + +static struct platform_driver sun8i_v3s_pinctrl_driver = { + .probe = sun8i_v3s_pinctrl_probe, + .driver = { + .name = "sun8i-v3s-pinctrl", + .of_match_table = sun8i_v3s_pinctrl_match, + }, +}; +builtin_platform_driver(sun8i_v3s_pinctrl_driver); From 670e9875eb14b112fa6a206a65c776a4fb347eb1 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Jan 2017 15:32:22 -0500 Subject: [PATCH 0351/1587] ext4: add debug_want_extra_isize mount option In order to test the inode extra isize expansion code, it is useful to be able to easily create file systems that have inodes with extra isize values smaller than the current desired value. Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9d15a6293124..829e4a7b59e4 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1284,7 +1284,7 @@ enum { Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, Opt_dax, Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit, - Opt_lazytime, Opt_nolazytime, + Opt_lazytime, Opt_nolazytime, Opt_debug_want_extra_isize, Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, Opt_inode_readahead_blks, Opt_journal_ioprio, Opt_dioread_nolock, Opt_dioread_lock, @@ -1352,6 +1352,7 @@ static const match_table_t tokens = { {Opt_delalloc, "delalloc"}, {Opt_lazytime, "lazytime"}, {Opt_nolazytime, "nolazytime"}, + {Opt_debug_want_extra_isize, "debug_want_extra_isize=%u"}, {Opt_nodelalloc, "nodelalloc"}, {Opt_removed, "mblk_io_submit"}, {Opt_removed, "nomblk_io_submit"}, @@ -1557,6 +1558,7 @@ static const struct mount_opts { #endif {Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET}, {Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET}, + {Opt_debug_want_extra_isize, 0, MOPT_GTE0}, {Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q}, {Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q}, @@ -1670,6 +1672,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, if (arg == 0) arg = JBD2_DEFAULT_MAX_COMMIT_AGE; sbi->s_commit_interval = HZ * arg; + } else if (token == Opt_debug_want_extra_isize) { + sbi->s_want_extra_isize = arg; } else if (token == Opt_max_batch_time) { sbi->s_max_batch_time = arg; } else if (token == Opt_min_batch_time) { @@ -4081,7 +4085,8 @@ no_journal: sb->s_flags |= MS_RDONLY; /* determine the minimum size of new large inodes, if present */ - if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { + if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE && + sbi->s_want_extra_isize == 0) { sbi->s_want_extra_isize = sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE; if (ext4_has_feature_extra_isize(sb)) { From c755e251357a0cee0679081f08c3f4ba797a8009 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Jan 2017 21:50:46 -0500 Subject: [PATCH 0352/1587] ext4: fix deadlock between inline_data and ext4_expand_extra_isize_ea() The xattr_sem deadlock problems fixed in commit 2e81a4eeedca: "ext4: avoid deadlock when expanding inode size" didn't include the use of xattr_sem in fs/ext4/inline.c. With the addition of project quota which added a new extra inode field, this exposed deadlocks in the inline_data code similar to the ones fixed by 2e81a4eeedca. The deadlock can be reproduced via: dmesg -n 7 mke2fs -t ext4 -O inline_data -Fq -I 256 /dev/vdc 32768 mount -t ext4 -o debug_want_extra_isize=24 /dev/vdc /vdc mkdir /vdc/a umount /vdc mount -t ext4 /dev/vdc /vdc echo foo > /vdc/a/foo and looks like this: [ 11.158815] [ 11.160276] ============================================= [ 11.161960] [ INFO: possible recursive locking detected ] [ 11.161960] 4.10.0-rc3-00015-g011b30a8a3cf #160 Tainted: G W [ 11.161960] --------------------------------------------- [ 11.161960] bash/2519 is trying to acquire lock: [ 11.161960] (&ei->xattr_sem){++++..}, at: [] ext4_expand_extra_isize_ea+0x3d/0x4cd [ 11.161960] [ 11.161960] but task is already holding lock: [ 11.161960] (&ei->xattr_sem){++++..}, at: [] ext4_try_add_inline_entry+0x3a/0x152 [ 11.161960] [ 11.161960] other info that might help us debug this: [ 11.161960] Possible unsafe locking scenario: [ 11.161960] [ 11.161960] CPU0 [ 11.161960] ---- [ 11.161960] lock(&ei->xattr_sem); [ 11.161960] lock(&ei->xattr_sem); [ 11.161960] [ 11.161960] *** DEADLOCK *** [ 11.161960] [ 11.161960] May be due to missing lock nesting notation [ 11.161960] [ 11.161960] 4 locks held by bash/2519: [ 11.161960] #0: (sb_writers#3){.+.+.+}, at: [] mnt_want_write+0x1e/0x3e [ 11.161960] #1: (&type->i_mutex_dir_key){++++++}, at: [] path_openat+0x338/0x67a [ 11.161960] #2: (jbd2_handle){++++..}, at: [] start_this_handle+0x582/0x622 [ 11.161960] #3: (&ei->xattr_sem){++++..}, at: [] ext4_try_add_inline_entry+0x3a/0x152 [ 11.161960] [ 11.161960] stack backtrace: [ 11.161960] CPU: 0 PID: 2519 Comm: bash Tainted: G W 4.10.0-rc3-00015-g011b30a8a3cf #160 [ 11.161960] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.1-1 04/01/2014 [ 11.161960] Call Trace: [ 11.161960] dump_stack+0x72/0xa3 [ 11.161960] __lock_acquire+0xb7c/0xcb9 [ 11.161960] ? kvm_clock_read+0x1f/0x29 [ 11.161960] ? __lock_is_held+0x36/0x66 [ 11.161960] ? __lock_is_held+0x36/0x66 [ 11.161960] lock_acquire+0x106/0x18a [ 11.161960] ? ext4_expand_extra_isize_ea+0x3d/0x4cd [ 11.161960] down_write+0x39/0x72 [ 11.161960] ? ext4_expand_extra_isize_ea+0x3d/0x4cd [ 11.161960] ext4_expand_extra_isize_ea+0x3d/0x4cd [ 11.161960] ? _raw_read_unlock+0x22/0x2c [ 11.161960] ? jbd2_journal_extend+0x1e2/0x262 [ 11.161960] ? __ext4_journal_get_write_access+0x3d/0x60 [ 11.161960] ext4_mark_inode_dirty+0x17d/0x26d [ 11.161960] ? ext4_add_dirent_to_inline.isra.12+0xa5/0xb2 [ 11.161960] ext4_add_dirent_to_inline.isra.12+0xa5/0xb2 [ 11.161960] ext4_try_add_inline_entry+0x69/0x152 [ 11.161960] ext4_add_entry+0xa3/0x848 [ 11.161960] ? __brelse+0x14/0x2f [ 11.161960] ? _raw_spin_unlock_irqrestore+0x44/0x4f [ 11.161960] ext4_add_nondir+0x17/0x5b [ 11.161960] ext4_create+0xcf/0x133 [ 11.161960] ? ext4_mknod+0x12f/0x12f [ 11.161960] lookup_open+0x39e/0x3fb [ 11.161960] ? __wake_up+0x1a/0x40 [ 11.161960] ? lock_acquire+0x11e/0x18a [ 11.161960] path_openat+0x35c/0x67a [ 11.161960] ? sched_clock_cpu+0xd7/0xf2 [ 11.161960] do_filp_open+0x36/0x7c [ 11.161960] ? _raw_spin_unlock+0x22/0x2c [ 11.161960] ? __alloc_fd+0x169/0x173 [ 11.161960] do_sys_open+0x59/0xcc [ 11.161960] SyS_open+0x1d/0x1f [ 11.161960] do_int80_syscall_32+0x4f/0x61 [ 11.161960] entry_INT80_32+0x2f/0x2f [ 11.161960] EIP: 0xb76ad469 [ 11.161960] EFLAGS: 00000286 CPU: 0 [ 11.161960] EAX: ffffffda EBX: 08168ac8 ECX: 00008241 EDX: 000001b6 [ 11.161960] ESI: b75e46bc EDI: b7755000 EBP: bfbdb108 ESP: bfbdafc0 [ 11.161960] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b Cc: stable@vger.kernel.org # 3.10 (requires 2e81a4eeedca as a prereq) Reported-by: George Spelvin Signed-off-by: Theodore Ts'o --- fs/ext4/inline.c | 66 ++++++++++++++++++++++-------------------------- fs/ext4/xattr.c | 30 +++++++++------------- fs/ext4/xattr.h | 32 +++++++++++++++++++++++ 3 files changed, 74 insertions(+), 54 deletions(-) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 437df6a1a841..99a5312ced52 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -381,7 +381,7 @@ out: static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, unsigned int len) { - int ret, size; + int ret, size, no_expand; struct ext4_inode_info *ei = EXT4_I(inode); if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) @@ -391,15 +391,14 @@ static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, if (size < len) return -ENOSPC; - down_write(&EXT4_I(inode)->xattr_sem); + ext4_write_lock_xattr(inode, &no_expand); if (ei->i_inline_off) ret = ext4_update_inline_data(handle, inode, len); else ret = ext4_create_inline_data(handle, inode, len); - up_write(&EXT4_I(inode)->xattr_sem); - + ext4_write_unlock_xattr(inode, &no_expand); return ret; } @@ -533,7 +532,7 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping, struct inode *inode, unsigned flags) { - int ret, needed_blocks; + int ret, needed_blocks, no_expand; handle_t *handle = NULL; int retries = 0, sem_held = 0; struct page *page = NULL; @@ -573,7 +572,7 @@ retry: goto out; } - down_write(&EXT4_I(inode)->xattr_sem); + ext4_write_lock_xattr(inode, &no_expand); sem_held = 1; /* If some one has already done this for us, just exit. */ if (!ext4_has_inline_data(inode)) { @@ -610,7 +609,7 @@ retry: put_page(page); page = NULL; ext4_orphan_add(handle, inode); - up_write(&EXT4_I(inode)->xattr_sem); + ext4_write_unlock_xattr(inode, &no_expand); sem_held = 0; ext4_journal_stop(handle); handle = NULL; @@ -636,7 +635,7 @@ out: put_page(page); } if (sem_held) - up_write(&EXT4_I(inode)->xattr_sem); + ext4_write_unlock_xattr(inode, &no_expand); if (handle) ext4_journal_stop(handle); brelse(iloc.bh); @@ -729,7 +728,7 @@ convert: int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, unsigned copied, struct page *page) { - int ret; + int ret, no_expand; void *kaddr; struct ext4_iloc iloc; @@ -747,7 +746,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, goto out; } - down_write(&EXT4_I(inode)->xattr_sem); + ext4_write_lock_xattr(inode, &no_expand); BUG_ON(!ext4_has_inline_data(inode)); kaddr = kmap_atomic(page); @@ -757,7 +756,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, /* clear page dirty so that writepages wouldn't work for us. */ ClearPageDirty(page); - up_write(&EXT4_I(inode)->xattr_sem); + ext4_write_unlock_xattr(inode, &no_expand); brelse(iloc.bh); out: return copied; @@ -768,7 +767,7 @@ ext4_journalled_write_inline_data(struct inode *inode, unsigned len, struct page *page) { - int ret; + int ret, no_expand; void *kaddr; struct ext4_iloc iloc; @@ -778,11 +777,11 @@ ext4_journalled_write_inline_data(struct inode *inode, return NULL; } - down_write(&EXT4_I(inode)->xattr_sem); + ext4_write_lock_xattr(inode, &no_expand); kaddr = kmap_atomic(page); ext4_write_inline_data(inode, &iloc, kaddr, 0, len); kunmap_atomic(kaddr); - up_write(&EXT4_I(inode)->xattr_sem); + ext4_write_unlock_xattr(inode, &no_expand); return iloc.bh; } @@ -1259,7 +1258,7 @@ out: int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, struct inode *dir, struct inode *inode) { - int ret, inline_size; + int ret, inline_size, no_expand; void *inline_start; struct ext4_iloc iloc; @@ -1267,7 +1266,7 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, if (ret) return ret; - down_write(&EXT4_I(dir)->xattr_sem); + ext4_write_lock_xattr(dir, &no_expand); if (!ext4_has_inline_data(dir)) goto out; @@ -1313,7 +1312,7 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, out: ext4_mark_inode_dirty(handle, dir); - up_write(&EXT4_I(dir)->xattr_sem); + ext4_write_unlock_xattr(dir, &no_expand); brelse(iloc.bh); return ret; } @@ -1673,7 +1672,7 @@ int ext4_delete_inline_entry(handle_t *handle, struct buffer_head *bh, int *has_inline_data) { - int err, inline_size; + int err, inline_size, no_expand; struct ext4_iloc iloc; void *inline_start; @@ -1681,7 +1680,7 @@ int ext4_delete_inline_entry(handle_t *handle, if (err) return err; - down_write(&EXT4_I(dir)->xattr_sem); + ext4_write_lock_xattr(dir, &no_expand); if (!ext4_has_inline_data(dir)) { *has_inline_data = 0; goto out; @@ -1715,7 +1714,7 @@ int ext4_delete_inline_entry(handle_t *handle, ext4_show_inline_dir(dir, iloc.bh, inline_start, inline_size); out: - up_write(&EXT4_I(dir)->xattr_sem); + ext4_write_unlock_xattr(dir, &no_expand); brelse(iloc.bh); if (err != -ENOENT) ext4_std_error(dir->i_sb, err); @@ -1814,11 +1813,11 @@ out: int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) { - int ret; + int ret, no_expand; - down_write(&EXT4_I(inode)->xattr_sem); + ext4_write_lock_xattr(inode, &no_expand); ret = ext4_destroy_inline_data_nolock(handle, inode); - up_write(&EXT4_I(inode)->xattr_sem); + ext4_write_unlock_xattr(inode, &no_expand); return ret; } @@ -1903,7 +1902,7 @@ out: void ext4_inline_data_truncate(struct inode *inode, int *has_inline) { handle_t *handle; - int inline_size, value_len, needed_blocks; + int inline_size, value_len, needed_blocks, no_expand; size_t i_size; void *value = NULL; struct ext4_xattr_ibody_find is = { @@ -1920,7 +1919,7 @@ void ext4_inline_data_truncate(struct inode *inode, int *has_inline) if (IS_ERR(handle)) return; - down_write(&EXT4_I(inode)->xattr_sem); + ext4_write_lock_xattr(inode, &no_expand); if (!ext4_has_inline_data(inode)) { *has_inline = 0; ext4_journal_stop(handle); @@ -1978,7 +1977,7 @@ out_error: up_write(&EXT4_I(inode)->i_data_sem); out: brelse(is.iloc.bh); - up_write(&EXT4_I(inode)->xattr_sem); + ext4_write_unlock_xattr(inode, &no_expand); kfree(value); if (inode->i_nlink) ext4_orphan_del(handle, inode); @@ -1994,7 +1993,7 @@ out: int ext4_convert_inline_data(struct inode *inode) { - int error, needed_blocks; + int error, needed_blocks, no_expand; handle_t *handle; struct ext4_iloc iloc; @@ -2016,15 +2015,10 @@ int ext4_convert_inline_data(struct inode *inode) goto out_free; } - down_write(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - up_write(&EXT4_I(inode)->xattr_sem); - goto out; - } - - error = ext4_convert_inline_data_nolock(handle, inode, &iloc); - up_write(&EXT4_I(inode)->xattr_sem); -out: + ext4_write_lock_xattr(inode, &no_expand); + if (ext4_has_inline_data(inode)) + error = ext4_convert_inline_data_nolock(handle, inode, &iloc); + ext4_write_unlock_xattr(inode, &no_expand); ext4_journal_stop(handle); out_free: brelse(iloc.bh); diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 5a94fa52b74f..c40bd55b6400 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1188,16 +1188,14 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, struct ext4_xattr_block_find bs = { .s = { .not_found = -ENODATA, }, }; - unsigned long no_expand; + int no_expand; int error; if (!name) return -EINVAL; if (strlen(name) > 255) return -ERANGE; - down_write(&EXT4_I(inode)->xattr_sem); - no_expand = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND); - ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND); + ext4_write_lock_xattr(inode, &no_expand); error = ext4_reserve_inode_write(handle, inode, &is.iloc); if (error) @@ -1264,7 +1262,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, ext4_xattr_update_super_block(handle, inode->i_sb); inode->i_ctime = current_time(inode); if (!value) - ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); + no_expand = 0; error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); /* * The bh is consumed by ext4_mark_iloc_dirty, even with @@ -1278,9 +1276,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, cleanup: brelse(is.iloc.bh); brelse(bs.bh); - if (no_expand == 0) - ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); - up_write(&EXT4_I(inode)->xattr_sem); + ext4_write_unlock_xattr(inode, &no_expand); return error; } @@ -1497,12 +1493,11 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, int error = 0, tried_min_extra_isize = 0; int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize); int isize_diff; /* How much do we need to grow i_extra_isize */ + int no_expand; + + if (ext4_write_trylock_xattr(inode, &no_expand) == 0) + return 0; - down_write(&EXT4_I(inode)->xattr_sem); - /* - * Set EXT4_STATE_NO_EXPAND to avoid recursion when marking inode dirty - */ - ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND); retry: isize_diff = new_extra_isize - EXT4_I(inode)->i_extra_isize; if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) @@ -1584,17 +1579,16 @@ shift: EXT4_I(inode)->i_extra_isize = new_extra_isize; brelse(bh); out: - ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); - up_write(&EXT4_I(inode)->xattr_sem); + ext4_write_unlock_xattr(inode, &no_expand); return 0; cleanup: brelse(bh); /* - * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode - * size expansion failed. + * Inode size expansion failed; don't try again */ - up_write(&EXT4_I(inode)->xattr_sem); + no_expand = 1; + ext4_write_unlock_xattr(inode, &no_expand); return error; } diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index a92e783fa057..099c8b670ef5 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -102,6 +102,38 @@ extern const struct xattr_handler ext4_xattr_security_handler; #define EXT4_XATTR_NAME_ENCRYPTION_CONTEXT "c" +/* + * The EXT4_STATE_NO_EXPAND is overloaded and used for two purposes. + * The first is to signal that there the inline xattrs and data are + * taking up so much space that we might as well not keep trying to + * expand it. The second is that xattr_sem is taken for writing, so + * we shouldn't try to recurse into the inode expansion. For this + * second case, we need to make sure that we take save and restore the + * NO_EXPAND state flag appropriately. + */ +static inline void ext4_write_lock_xattr(struct inode *inode, int *save) +{ + down_write(&EXT4_I(inode)->xattr_sem); + *save = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND); + ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND); +} + +static inline int ext4_write_trylock_xattr(struct inode *inode, int *save) +{ + if (down_write_trylock(&EXT4_I(inode)->xattr_sem) == 0) + return 0; + *save = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND); + ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND); + return 1; +} + +static inline void ext4_write_unlock_xattr(struct inode *inode, int *save) +{ + if (*save == 0) + ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); + up_write(&EXT4_I(inode)->xattr_sem); +} + extern ssize_t ext4_listxattr(struct dentry *, char *, size_t); extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t); From b907f2d5194c2636623415d89cfb91d692af0629 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Jan 2017 22:14:49 -0500 Subject: [PATCH 0353/1587] ext4: avoid calling ext4_mark_inode_dirty() under unneeded semaphores There is no need to call ext4_mark_inode_dirty while holding xattr_sem or i_data_sem, so where it's easy to avoid it, move it out from the critical region. Signed-off-by: Theodore Ts'o --- fs/ext4/inline.c | 9 +++------ fs/ext4/inode.c | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 99a5312ced52..31f98dd04e51 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -1042,7 +1042,6 @@ static int ext4_add_dirent_to_inline(handle_t *handle, dir->i_mtime = dir->i_ctime = current_time(dir); ext4_update_dx_flag(dir); dir->i_version++; - ext4_mark_inode_dirty(handle, dir); return 1; } @@ -1311,8 +1310,8 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, ret = ext4_convert_inline_data_nolock(handle, dir, &iloc); out: - ext4_mark_inode_dirty(handle, dir); ext4_write_unlock_xattr(dir, &no_expand); + ext4_mark_inode_dirty(handle, dir); brelse(iloc.bh); return ret; } @@ -1708,13 +1707,11 @@ int ext4_delete_inline_entry(handle_t *handle, if (err) goto out; - err = ext4_mark_inode_dirty(handle, dir); - if (unlikely(err)) - goto out; - ext4_show_inline_dir(dir, iloc.bh, inline_start, inline_size); out: ext4_write_unlock_xattr(dir, &no_expand); + if (likely(err == 0)) + err = ext4_mark_inode_dirty(handle, dir); brelse(iloc.bh); if (err != -ENOENT) ext4_std_error(dir->i_sb, err); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 88d57af1b516..86dde0667ccc 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2464,8 +2464,8 @@ update_disksize: disksize = i_size; if (disksize > EXT4_I(inode)->i_disksize) EXT4_I(inode)->i_disksize = disksize; - err2 = ext4_mark_inode_dirty(handle, inode); up_write(&EXT4_I(inode)->i_data_sem); + err2 = ext4_mark_inode_dirty(handle, inode); if (err2) ext4_error(inode->i_sb, "Failed to mark inode %lu dirty", From 2e48e3491189c40dc9ea9d4a53412d2b66c87555 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 18 Nov 2016 07:02:38 +0100 Subject: [PATCH 0354/1587] scsi: vmw_pvscsi: switch to pci_alloc_irq_vectors And simplify the interrupt handler by splitting the INTx case that needs to deal with shared interrupts into a separate helper. [mkp: typo fixage] Signed-off-by: Christoph Hellwig Acked-by: Jim Gill Signed-off-by: Martin K. Petersen --- drivers/scsi/vmw_pvscsi.c | 104 ++++++++++++++------------------------ drivers/scsi/vmw_pvscsi.h | 5 -- 2 files changed, 38 insertions(+), 71 deletions(-) diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 15ca09cd16f3..ef474a748744 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -68,10 +68,7 @@ struct pvscsi_ctx { struct pvscsi_adapter { char *mmioBase; - unsigned int irq; u8 rev; - bool use_msi; - bool use_msix; bool use_msg; bool use_req_threshold; @@ -1161,30 +1158,26 @@ static bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter, static irqreturn_t pvscsi_isr(int irq, void *devp) { struct pvscsi_adapter *adapter = devp; - int handled; + unsigned long flags; - if (adapter->use_msi || adapter->use_msix) - handled = true; - else { - u32 val = pvscsi_read_intr_status(adapter); - handled = (val & PVSCSI_INTR_ALL_SUPPORTED) != 0; - if (handled) - pvscsi_write_intr_status(devp, val); - } + spin_lock_irqsave(&adapter->hw_lock, flags); + pvscsi_process_completion_ring(adapter); + if (adapter->use_msg && pvscsi_msg_pending(adapter)) + queue_work(adapter->workqueue, &adapter->work); + spin_unlock_irqrestore(&adapter->hw_lock, flags); - if (handled) { - unsigned long flags; + return IRQ_HANDLED; +} - spin_lock_irqsave(&adapter->hw_lock, flags); +static irqreturn_t pvscsi_shared_isr(int irq, void *devp) +{ + struct pvscsi_adapter *adapter = devp; + u32 val = pvscsi_read_intr_status(adapter); - pvscsi_process_completion_ring(adapter); - if (adapter->use_msg && pvscsi_msg_pending(adapter)) - queue_work(adapter->workqueue, &adapter->work); - - spin_unlock_irqrestore(&adapter->hw_lock, flags); - } - - return IRQ_RETVAL(handled); + if (!(val & PVSCSI_INTR_ALL_SUPPORTED)) + return IRQ_NONE; + pvscsi_write_intr_status(devp, val); + return pvscsi_isr(irq, devp); } static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) @@ -1196,34 +1189,10 @@ static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE)); } -static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, - unsigned int *irq) -{ - struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION }; - int ret; - - ret = pci_enable_msix_exact(adapter->dev, &entry, 1); - if (ret) - return ret; - - *irq = entry.vector; - - return 0; -} - static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter) { - if (adapter->irq) { - free_irq(adapter->irq, adapter); - adapter->irq = 0; - } - if (adapter->use_msi) { - pci_disable_msi(adapter->dev); - adapter->use_msi = 0; - } else if (adapter->use_msix) { - pci_disable_msix(adapter->dev); - adapter->use_msix = 0; - } + free_irq(pci_irq_vector(adapter->dev, 0), adapter); + pci_free_irq_vectors(adapter->dev); } static void pvscsi_release_resources(struct pvscsi_adapter *adapter) @@ -1359,11 +1328,11 @@ exit: static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + unsigned int irq_flag = PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY; struct pvscsi_adapter *adapter; struct pvscsi_adapter adapter_temp; struct Scsi_Host *host = NULL; unsigned int i; - unsigned long flags = 0; int error; u32 max_id; @@ -1512,30 +1481,33 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_reset_adapter; } - if (!pvscsi_disable_msix && - pvscsi_setup_msix(adapter, &adapter->irq) == 0) { - printk(KERN_INFO "vmw_pvscsi: using MSI-X\n"); - adapter->use_msix = 1; - } else if (!pvscsi_disable_msi && pci_enable_msi(pdev) == 0) { - printk(KERN_INFO "vmw_pvscsi: using MSI\n"); - adapter->use_msi = 1; - adapter->irq = pdev->irq; - } else { - printk(KERN_INFO "vmw_pvscsi: using INTx\n"); - adapter->irq = pdev->irq; - flags = IRQF_SHARED; - } + if (pvscsi_disable_msix) + irq_flag &= ~PCI_IRQ_MSIX; + if (pvscsi_disable_msi) + irq_flag &= ~PCI_IRQ_MSI; + + error = pci_alloc_irq_vectors(adapter->dev, 1, 1, irq_flag); + if (error) + goto out_reset_adapter; adapter->use_req_threshold = pvscsi_setup_req_threshold(adapter, true); printk(KERN_DEBUG "vmw_pvscsi: driver-based request coalescing %sabled\n", adapter->use_req_threshold ? "en" : "dis"); - error = request_irq(adapter->irq, pvscsi_isr, flags, - "vmw_pvscsi", adapter); + if (adapter->dev->msix_enabled || adapter->dev->msi_enabled) { + printk(KERN_INFO "vmw_pvscsi: using MSI%s\n", + adapter->dev->msix_enabled ? "-X" : ""); + error = request_irq(pci_irq_vector(pdev, 0), pvscsi_isr, + 0, "vmw_pvscsi", adapter); + } else { + printk(KERN_INFO "vmw_pvscsi: using INTx\n"); + error = request_irq(pci_irq_vector(pdev, 0), pvscsi_shared_isr, + IRQF_SHARED, "vmw_pvscsi", adapter); + } + if (error) { printk(KERN_ERR "vmw_pvscsi: unable to request IRQ: %d\n", error); - adapter->irq = 0; goto out_reset_adapter; } diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h index d41292ef85f2..75966d3f326e 100644 --- a/drivers/scsi/vmw_pvscsi.h +++ b/drivers/scsi/vmw_pvscsi.h @@ -422,11 +422,6 @@ struct PVSCSIConfigPageController { */ #define PVSCSI_MAX_INTRS 24 -/* - * Enumeration of supported MSI-X vectors - */ -#define PVSCSI_VECTOR_COMPLETION 0 - /* * Misc constants for the rings. */ From 73eba2be9203c0eef37df6939ebba4d34227f284 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Tue, 10 Jan 2017 16:48:25 -0800 Subject: [PATCH 0355/1587] scsi: ufs: fix arguments order some trace calls Colin Ian King reported that with commit 7ff5ab473633 ("scsi: ufs: add tracing support") static analysis is reporting that we may have swapped arguments on calls to: trace_ufshcd_runtime_resume, trace_ufshcd_runtime_suspend, trace_ufshcd_system_suspend, trace_ufshcd_system_resume, and trace_ufshcd_init Where: hba->uic_link_state is passed to dev_state hba->curr_dev_pwr_mode is passed to link_state This wasn't intentional so it's a bug. This change fixed this bug. Reported-by: Colin Ian King Signed-off-by: Subhash Jadavani Acked-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index dfad19ff166c..a70bf066f277 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5803,7 +5803,7 @@ out: trace_ufshcd_init(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), - hba->uic_link_state, hba->curr_dev_pwr_mode); + hba->curr_dev_pwr_mode, hba->uic_link_state); return ret; } @@ -6817,7 +6817,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba) out: trace_ufshcd_system_suspend(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), - hba->uic_link_state, hba->curr_dev_pwr_mode); + hba->curr_dev_pwr_mode, hba->uic_link_state); if (!ret) hba->is_sys_suspended = true; return ret; @@ -6850,7 +6850,7 @@ int ufshcd_system_resume(struct ufs_hba *hba) out: trace_ufshcd_system_resume(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), - hba->uic_link_state, hba->curr_dev_pwr_mode); + hba->curr_dev_pwr_mode, hba->uic_link_state); return ret; } EXPORT_SYMBOL(ufshcd_system_resume); @@ -6878,7 +6878,7 @@ int ufshcd_runtime_suspend(struct ufs_hba *hba) out: trace_ufshcd_runtime_suspend(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), - hba->uic_link_state, hba->curr_dev_pwr_mode); + hba->curr_dev_pwr_mode, hba->uic_link_state); return ret; } EXPORT_SYMBOL(ufshcd_runtime_suspend); @@ -6919,7 +6919,7 @@ int ufshcd_runtime_resume(struct ufs_hba *hba) out: trace_ufshcd_runtime_resume(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), - hba->uic_link_state, hba->curr_dev_pwr_mode); + hba->curr_dev_pwr_mode, hba->uic_link_state); return ret; } EXPORT_SYMBOL(ufshcd_runtime_resume); From 9c7d1ee5f13a7130f6d3df307ec010e9e003fa98 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 11 Jan 2017 19:19:08 -0600 Subject: [PATCH 0356/1587] scsi: cxlflash: Refactor context reset to share reset logic As staging for supporting hardware with different context reset registers but a similar reset procedure, refactor the existing context reset routine to move the reset logic to a common routine. This will allow hardware with a different reset register to leverage existing code. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index b17ebf6d0a7e..a990efb27197 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -188,10 +188,11 @@ static void cmd_complete(struct afu_cmd *cmd) } /** - * context_reset_ioarrin() - reset command owner context via IOARRIN register + * context_reset() - reset command owner context via specified register * @cmd: AFU command that timed out. + * @reset_reg: MMIO register to perform reset. */ -static void context_reset_ioarrin(struct afu_cmd *cmd) +static void context_reset(struct afu_cmd *cmd, __be64 __iomem *reset_reg) { int nretry = 0; u64 rrin = 0x1; @@ -201,9 +202,9 @@ static void context_reset_ioarrin(struct afu_cmd *cmd) pr_debug("%s: cmd=%p\n", __func__, cmd); - writeq_be(rrin, &afu->host_map->ioarrin); + writeq_be(rrin, reset_reg); do { - rrin = readq_be(&afu->host_map->ioarrin); + rrin = readq_be(reset_reg); if (rrin != 0x1) break; /* Double delay each time */ @@ -214,6 +215,17 @@ static void context_reset_ioarrin(struct afu_cmd *cmd) __func__, rrin, nretry); } +/** + * context_reset_ioarrin() - reset command owner context via IOARRIN register + * @cmd: AFU command that timed out. + */ +static void context_reset_ioarrin(struct afu_cmd *cmd) +{ + struct afu *afu = cmd->parent; + + context_reset(cmd, &afu->host_map->ioarrin); +} + /** * send_cmd_ioarrin() - sends an AFU command via IOARRIN register * @afu: AFU associated with the host. From 696d0b0c715360ce28fedd3c8b009d3771a5ddeb Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 11 Jan 2017 19:19:33 -0600 Subject: [PATCH 0357/1587] scsi: cxlflash: Support SQ Command Mode The SISLite specification outlines a new queuing model to improve over the MMIO-based IOARRIN model that exists today. This new model uses a submission queue that exists in host memory and is shared with the device. Each entry in the queue is an IOARCB that describes a transfer request. When requests are submitted, IOARCBs ('current' position tracked in host software) are populated and the submission queue tail pointer is then updated via MMIO to make the device aware of the requests. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 30 ++++++++- drivers/scsi/cxlflash/main.c | 98 ++++++++++++++++++++++++++++-- drivers/scsi/cxlflash/sislite.h | 19 +++++- drivers/scsi/cxlflash/superpipe.c | 18 ++++-- include/uapi/scsi/cxlflash_ioctl.h | 1 + 5 files changed, 153 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 0e9de5d62da2..dee865735ac0 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -54,6 +54,9 @@ extern const struct file_operations cxlflash_cxl_fops; /* RRQ for master issued cmds */ #define NUM_RRQ_ENTRY CXLFLASH_MAX_CMDS +/* SQ for master issued cmds */ +#define NUM_SQ_ENTRY CXLFLASH_MAX_CMDS + static inline void check_sizes(void) { @@ -155,8 +158,8 @@ static inline struct afu_cmd *sc_to_afucz(struct scsi_cmnd *sc) struct afu { /* Stuff requiring alignment go first. */ - - u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */ + struct sisl_ioarcb sq[NUM_SQ_ENTRY]; /* 16K SQ */ + u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */ /* Beware of alignment till here. Preferably introduce new * fields after this point @@ -174,6 +177,12 @@ struct afu { struct kref mapcount; ctx_hndl_t ctx_hndl; /* master's context handle */ + + atomic_t hsq_credits; + spinlock_t hsq_slock; + struct sisl_ioarcb *hsq_start; + struct sisl_ioarcb *hsq_end; + struct sisl_ioarcb *hsq_curr; u64 *hrrq_start; u64 *hrrq_end; u64 *hrrq_curr; @@ -191,6 +200,23 @@ struct afu { }; +static inline bool afu_is_cmd_mode(struct afu *afu, u64 cmd_mode) +{ + u64 afu_cap = afu->interface_version >> SISL_INTVER_CAP_SHIFT; + + return afu_cap & cmd_mode; +} + +static inline bool afu_is_sq_cmd_mode(struct afu *afu) +{ + return afu_is_cmd_mode(afu, SISL_INTVER_CAP_SQ_CMD_MODE); +} + +static inline bool afu_is_ioarrin_cmd_mode(struct afu *afu) +{ + return afu_is_cmd_mode(afu, SISL_INTVER_CAP_IOARRIN_CMD_MODE); +} + static inline u64 lun_to_lunid(u64 lun) { __be64 lun_id; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index a990efb27197..d2bac4b7b85f 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -226,6 +226,17 @@ static void context_reset_ioarrin(struct afu_cmd *cmd) context_reset(cmd, &afu->host_map->ioarrin); } +/** + * context_reset_sq() - reset command owner context w/ SQ Context Reset register + * @cmd: AFU command that timed out. + */ +static void context_reset_sq(struct afu_cmd *cmd) +{ + struct afu *afu = cmd->parent; + + context_reset(cmd, &afu->host_map->sq_ctx_reset); +} + /** * send_cmd_ioarrin() - sends an AFU command via IOARRIN register * @afu: AFU associated with the host. @@ -268,6 +279,49 @@ out: return rc; } +/** + * send_cmd_sq() - sends an AFU command via SQ ring + * @afu: AFU associated with the host. + * @cmd: AFU command to send. + * + * Return: + * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure + */ +static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd) +{ + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; + int rc = 0; + int newval; + ulong lock_flags; + + newval = atomic_dec_if_positive(&afu->hsq_credits); + if (newval <= 0) { + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } + + cmd->rcb.ioasa = &cmd->sa; + + spin_lock_irqsave(&afu->hsq_slock, lock_flags); + + *afu->hsq_curr = cmd->rcb; + if (afu->hsq_curr < afu->hsq_end) + afu->hsq_curr++; + else + afu->hsq_curr = afu->hsq_start; + writeq_be((u64)afu->hsq_curr, &afu->host_map->sq_tail); + + spin_unlock_irqrestore(&afu->hsq_slock, lock_flags); +out: + dev_dbg(dev, "%s: cmd=%p len=%d ea=%p ioasa=%p rc=%d curr=%p " + "head=%016llX tail=%016llX\n", __func__, cmd, cmd->rcb.data_len, + (void *)cmd->rcb.data_ea, cmd->rcb.ioasa, rc, afu->hsq_curr, + readq_be(&afu->host_map->sq_head), + readq_be(&afu->host_map->sq_tail)); + return rc; +} + /** * wait_resp() - polls for a response or timeout to a sent AFU command * @afu: AFU associated with the host. @@ -739,7 +793,7 @@ static int alloc_mem(struct cxlflash_cfg *cfg) int rc = 0; struct device *dev = &cfg->dev->dev; - /* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */ + /* AFU is ~28k, i.e. only one 64k page or up to seven 4k pages */ cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(sizeof(struct afu))); if (unlikely(!cfg->afu)) { @@ -1127,6 +1181,8 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) { struct afu *afu = (struct afu *)data; struct afu_cmd *cmd; + struct sisl_ioasa *ioasa; + struct sisl_ioarcb *ioarcb; bool toggle = afu->toggle; u64 entry, *hrrq_start = afu->hrrq_start, @@ -1140,7 +1196,16 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) if ((entry & SISL_RESP_HANDLE_T_BIT) != toggle) break; - cmd = (struct afu_cmd *)(entry & ~SISL_RESP_HANDLE_T_BIT); + entry &= ~SISL_RESP_HANDLE_T_BIT; + + if (afu_is_sq_cmd_mode(afu)) { + ioasa = (struct sisl_ioasa *)entry; + cmd = container_of(ioasa, struct afu_cmd, sa); + } else { + ioarcb = (struct sisl_ioarcb *)entry; + cmd = container_of(ioarcb, struct afu_cmd, rcb); + } + cmd_complete(cmd); /* Advance to next entry or wrap and flip the toggle bit */ @@ -1150,6 +1215,8 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) hrrq_curr = hrrq_start; toggle ^= SISL_RESP_HANDLE_T_BIT; } + + atomic_inc(&afu->hsq_credits); } afu->hrrq_curr = hrrq_curr; @@ -1402,10 +1469,15 @@ static int init_global(struct cxlflash_cfg *cfg) pr_debug("%s: wwpn0=0x%llX wwpn1=0x%llX\n", __func__, wwpn[0], wwpn[1]); - /* Set up RRQ in AFU for master issued cmds */ + /* Set up RRQ and SQ in AFU for master issued cmds */ writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start); writeq_be((u64) afu->hrrq_end, &afu->host_map->rrq_end); + if (afu_is_sq_cmd_mode(afu)) { + writeq_be((u64)afu->hsq_start, &afu->host_map->sq_start); + writeq_be((u64)afu->hsq_end, &afu->host_map->sq_end); + } + /* AFU configuration */ reg = readq_be(&afu->afu_map->global.regs.afu_config); reg |= SISL_AFUCONF_AR_ALL|SISL_AFUCONF_ENDIAN; @@ -1480,6 +1552,17 @@ static int start_afu(struct cxlflash_cfg *cfg) afu->hrrq_curr = afu->hrrq_start; afu->toggle = 1; + /* Initialize SQ */ + if (afu_is_sq_cmd_mode(afu)) { + memset(&afu->sq, 0, sizeof(afu->sq)); + afu->hsq_start = &afu->sq[0]; + afu->hsq_end = &afu->sq[NUM_SQ_ENTRY - 1]; + afu->hsq_curr = afu->hsq_start; + + spin_lock_init(&afu->hsq_slock); + atomic_set(&afu->hsq_credits, NUM_SQ_ENTRY - 1); + } + rc = init_global(cfg); pr_debug("%s: returning rc=%d\n", __func__, rc); @@ -1641,8 +1724,13 @@ static int init_afu(struct cxlflash_cfg *cfg) goto err2; } - afu->send_cmd = send_cmd_ioarrin; - afu->context_reset = context_reset_ioarrin; + if (afu_is_sq_cmd_mode(afu)) { + afu->send_cmd = send_cmd_sq; + afu->context_reset = context_reset_sq; + } else { + afu->send_cmd = send_cmd_ioarrin; + afu->context_reset = context_reset_ioarrin; + } pr_debug("%s: afu version %s, interface version 0x%llX\n", __func__, afu->version, afu->interface_version); diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 1a2d09c148b3..a6e48a893fef 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -72,7 +72,10 @@ struct sisl_ioarcb { u16 timeout; /* in units specified by req_flags */ u32 rsvd1; u8 cdb[16]; /* must be in big endian */ - u64 reserved; /* Reserved area */ + union { + u64 reserved; /* Reserved for IOARRIN mode */ + struct sisl_ioasa *ioasa; /* IOASA EA for SQ Mode */ + }; } __packed; struct sisl_rc { @@ -260,6 +263,11 @@ struct sisl_host_map { __be64 cmd_room; __be64 ctx_ctrl; /* least significant byte or b56:63 is LISN# */ __be64 mbox_w; /* restricted use */ + __be64 sq_start; /* Submission Queue (R/W): write sequence and */ + __be64 sq_end; /* inclusion semantics are the same as RRQ */ + __be64 sq_head; /* Submission Queue Head (R): for debugging */ + __be64 sq_tail; /* Submission Queue TAIL (R/W): next IOARCB */ + __be64 sq_ctx_reset; /* Submission Queue Context Reset (R/W) */ }; /* per context provisioning & control MMIO */ @@ -348,6 +356,15 @@ struct sisl_global_regs { __be64 rsvd[0xf8]; __le64 afu_version; __be64 interface_version; +#define SISL_INTVER_CAP_SHIFT 16 +#define SISL_INTVER_MAJ_SHIFT 8 +#define SISL_INTVER_CAP_MASK 0xFFFFFFFF00000000ULL +#define SISL_INTVER_MAJ_MASK 0x00000000FFFF0000ULL +#define SISL_INTVER_MIN_MASK 0x000000000000FFFFULL +#define SISL_INTVER_CAP_IOARRIN_CMD_MODE 0x800000000000ULL +#define SISL_INTVER_CAP_SQ_CMD_MODE 0x400000000000ULL +#define SISL_INTVER_CAP_RESERVED_CMD_MODE_A 0x200000000000ULL +#define SISL_INTVER_CAP_RESERVED_CMD_MODE_B 0x100000000000ULL }; #define CXLFLASH_NUM_FC_PORTS 2 diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 9636970d9611..42674ae6f4dd 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -1287,6 +1287,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, int rc = 0; u32 perms; int ctxid = -1; + u64 flags = 0UL; u64 rctxid = 0UL; struct file *file = NULL; @@ -1426,10 +1427,11 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, out_attach: if (fd != -1) - attach->hdr.return_flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD; - else - attach->hdr.return_flags = 0; + flags |= DK_CXLFLASH_APP_CLOSE_ADAP_FD; + if (afu_is_sq_cmd_mode(afu)) + flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE; + attach->hdr.return_flags = flags; attach->context_id = ctxi->ctxid; attach->block_size = gli->blk_len; attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); @@ -1617,6 +1619,7 @@ static int cxlflash_afu_recover(struct scsi_device *sdev, struct afu *afu = cfg->afu; struct ctx_info *ctxi = NULL; struct mutex *mutex = &cfg->ctx_recovery_mutex; + u64 flags; u64 ctxid = DECODE_CTXID(recover->context_id), rctxid = recover->context_id; long reg; @@ -1672,11 +1675,16 @@ retry_recover: } ctxi->err_recovery_active = false; + + flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD | + DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET; + if (afu_is_sq_cmd_mode(afu)) + flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE; + + recover->hdr.return_flags = flags; recover->context_id = ctxi->ctxid; recover->adap_fd = new_adap_fd; recover->mmio_size = sizeof(afu->afu_map->hosts[0].harea); - recover->hdr.return_flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD | - DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET; goto out; } diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h index 6bf1f8a022b1..e9fdc12ad984 100644 --- a/include/uapi/scsi/cxlflash_ioctl.h +++ b/include/uapi/scsi/cxlflash_ioctl.h @@ -40,6 +40,7 @@ struct dk_cxlflash_hdr { */ #define DK_CXLFLASH_ALL_PORTS_ACTIVE 0x0000000000000001ULL #define DK_CXLFLASH_APP_CLOSE_ADAP_FD 0x0000000000000002ULL +#define DK_CXLFLASH_CONTEXT_SQ_CMD_MODE 0x0000000000000004ULL /* * General Notes: From fb67d44dfbdf85d984b9b40284e90636a3a7b21d Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 11 Jan 2017 19:19:47 -0600 Subject: [PATCH 0358/1587] scsi: cxlflash: Cleanup prints The usage of prints within the cxlflash driver is inconsistent. This hinders debug and makes the driver source and log output appear sloppy. The following cleanups help unify the prints within cxlflash: - move all prints to dev-* where possible - transition all hex prints to lowercase - standardize variable prints in debug output - derive pointers in a consistent manner - change int to bool where appropriate - remove superfluous data from prints and print statements that do not make sense Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Reviewed-by: Andrew Donnellan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/lunmgt.c | 31 +-- drivers/scsi/cxlflash/main.c | 319 ++++++++++++++---------------- drivers/scsi/cxlflash/superpipe.c | 165 ++++++++-------- drivers/scsi/cxlflash/vlun.c | 169 ++++++++-------- 4 files changed, 346 insertions(+), 338 deletions(-) diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index 6c318db90c85..0efed177cc8b 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -32,11 +32,13 @@ */ static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = NULL; lli = kzalloc(sizeof(*lli), GFP_KERNEL); if (unlikely(!lli)) { - pr_err("%s: could not allocate lli\n", __func__); + dev_err(dev, "%s: could not allocate lli\n", __func__); goto out; } @@ -58,11 +60,13 @@ out: */ static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct glun_info *gli = NULL; gli = kzalloc(sizeof(*gli), GFP_KERNEL); if (unlikely(!gli)) { - pr_err("%s: could not allocate gli\n", __func__); + dev_err(dev, "%s: could not allocate gli\n", __func__); goto out; } @@ -129,10 +133,10 @@ static struct glun_info *lookup_global(u8 *wwid) */ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = NULL; struct glun_info *gli = NULL; - struct Scsi_Host *shost = sdev->host; - struct cxlflash_cfg *cfg = shost_priv(shost); if (unlikely(!wwid)) goto out; @@ -165,7 +169,7 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) list_add(&gli->list, &global.gluns); out: - pr_debug("%s: returning %p\n", __func__, lli); + dev_dbg(dev, "%s: returning lli=%p, gli=%p\n", __func__, lli, gli); return lli; } @@ -225,17 +229,18 @@ void cxlflash_term_global_luns(void) int cxlflash_manage_lun(struct scsi_device *sdev, struct dk_cxlflash_manage_lun *manage) { - int rc = 0; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = NULL; + int rc = 0; u64 flags = manage->hdr.flags; u32 chan = sdev->channel; mutex_lock(&global.mutex); lli = find_and_create_lun(sdev, manage->wwid); - pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n", - __func__, get_unaligned_be64(&manage->wwid[0]), - get_unaligned_be64(&manage->wwid[8]), - manage->hdr.flags, lli); + dev_dbg(dev, "%s: WWID=%016llx%016llx, flags=%016llx lli=%p\n", + __func__, get_unaligned_be64(&manage->wwid[0]), + get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli); if (unlikely(!lli)) { rc = -ENOMEM; goto out; @@ -265,11 +270,11 @@ int cxlflash_manage_lun(struct scsi_device *sdev, } } - pr_debug("%s: port_sel = %08X chan = %u lun_id = %016llX\n", __func__, - lli->port_sel, chan, lli->lun_id[chan]); + dev_dbg(dev, "%s: port_sel=%08x chan=%u lun_id=%016llx\n", + __func__, lli->port_sel, chan, lli->lun_id[chan]); out: mutex_unlock(&global.mutex); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index d2bac4b7b85f..ab38bca5df2b 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -43,6 +43,9 @@ MODULE_LICENSE("GPL"); */ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) { + struct afu *afu = cmd->parent; + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; struct sisl_ioarcb *ioarcb; struct sisl_ioasa *ioasa; u32 resid; @@ -56,21 +59,20 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) { resid = ioasa->resid; scsi_set_resid(scp, resid); - pr_debug("%s: cmd underrun cmd = %p scp = %p, resid = %d\n", - __func__, cmd, scp, resid); + dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p, resid = %d\n", + __func__, cmd, scp, resid); } if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) { - pr_debug("%s: cmd underrun cmd = %p scp = %p\n", - __func__, cmd, scp); + dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p\n", + __func__, cmd, scp); scp->result = (DID_ERROR << 16); } - pr_debug("%s: cmd failed afu_rc=%d scsi_rc=%d fc_rc=%d " - "afu_extra=0x%X, scsi_extra=0x%X, fc_extra=0x%X\n", - __func__, ioasa->rc.afu_rc, ioasa->rc.scsi_rc, - ioasa->rc.fc_rc, ioasa->afu_extra, ioasa->scsi_extra, - ioasa->fc_extra); + dev_dbg(dev, "%s: cmd failed afu_rc=%02x scsi_rc=%02x fc_rc=%02x " + "afu_extra=%02x scsi_extra=%02x fc_extra=%02x\n", __func__, + ioasa->rc.afu_rc, ioasa->rc.scsi_rc, ioasa->rc.fc_rc, + ioasa->afu_extra, ioasa->scsi_extra, ioasa->fc_extra); if (ioasa->rc.scsi_rc) { /* We have a SCSI status */ @@ -159,6 +161,7 @@ static void cmd_complete(struct afu_cmd *cmd) ulong lock_flags; struct afu *afu = cmd->parent; struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; bool cmd_is_tmf; if (cmd->scp) { @@ -170,9 +173,8 @@ static void cmd_complete(struct afu_cmd *cmd) cmd_is_tmf = cmd->cmd_tmf; - pr_debug_ratelimited("%s: calling scsi_done scp=%p result=%X " - "ioasc=%d\n", __func__, scp, scp->result, - cmd->sa.ioasc); + dev_dbg_ratelimited(dev, "%s:scp=%p result=%08x ioasc=%08x\n", + __func__, scp, scp->result, cmd->sa.ioasc); scsi_dma_unmap(scp); scp->scsi_done(scp); @@ -200,7 +202,7 @@ static void context_reset(struct afu_cmd *cmd, __be64 __iomem *reset_reg) struct cxlflash_cfg *cfg = afu->parent; struct device *dev = &cfg->dev->dev; - pr_debug("%s: cmd=%p\n", __func__, cmd); + dev_dbg(dev, "%s: cmd=%p\n", __func__, cmd); writeq_be(rrin, reset_reg); do { @@ -211,7 +213,7 @@ static void context_reset(struct afu_cmd *cmd, __be64 __iomem *reset_reg) udelay(1 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); - dev_dbg(dev, "%s: returning rrin=0x%016llX nretry=%d\n", + dev_dbg(dev, "%s: returning rrin=%016llx nretry=%d\n", __func__, rrin, nretry); } @@ -274,8 +276,8 @@ static int send_cmd_ioarrin(struct afu *afu, struct afu_cmd *cmd) writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin); out: spin_unlock_irqrestore(&afu->rrin_slock, lock_flags); - pr_devel("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd, - cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc); + dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx rc=%d\n", __func__, + cmd, cmd->rcb.data_len, cmd->rcb.data_ea, rc); return rc; } @@ -314,9 +316,9 @@ static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd) spin_unlock_irqrestore(&afu->hsq_slock, lock_flags); out: - dev_dbg(dev, "%s: cmd=%p len=%d ea=%p ioasa=%p rc=%d curr=%p " - "head=%016llX tail=%016llX\n", __func__, cmd, cmd->rcb.data_len, - (void *)cmd->rcb.data_ea, cmd->rcb.ioasa, rc, afu->hsq_curr, + dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx ioasa=%p rc=%d curr=%p " + "head=%016llx tail=%016llx\n", __func__, cmd, cmd->rcb.data_len, + cmd->rcb.data_ea, cmd->rcb.ioasa, rc, afu->hsq_curr, readq_be(&afu->host_map->sq_head), readq_be(&afu->host_map->sq_tail)); return rc; @@ -332,6 +334,8 @@ out: */ static int wait_resp(struct afu *afu, struct afu_cmd *cmd) { + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; int rc = 0; ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000); @@ -342,10 +346,8 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd) } if (unlikely(cmd->sa.ioasc != 0)) { - pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, " - "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0], - cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc, - cmd->sa.rc.fc_rc); + dev_err(dev, "%s: cmd %02x failed, ioasc=%08x\n", + __func__, cmd->rcb.cdb[0], cmd->sa.ioasc); rc = -1; } @@ -364,8 +366,7 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd) static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) { u32 port_sel = scp->device->channel + 1; - struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(scp->device->host); struct afu_cmd *cmd = sc_to_afucz(scp); struct device *dev = &cfg->dev->dev; ulong lock_flags; @@ -410,7 +411,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) to); if (!to) { cfg->tmf_active = false; - dev_err(dev, "%s: TMF timed out!\n", __func__); + dev_err(dev, "%s: TMF timed out\n", __func__); rc = -1; } spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); @@ -448,7 +449,7 @@ static const char *cxlflash_driver_info(struct Scsi_Host *host) */ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(host); struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd = sc_to_afucz(scp); @@ -461,7 +462,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) int kref_got = 0; dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", + "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no, scp->device->channel, scp->device->id, scp->device->lun, get_unaligned_be32(&((u32 *)scp->cmnd)[0]), @@ -483,11 +484,11 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) switch (cfg->state) { case STATE_RESET: - dev_dbg_ratelimited(dev, "%s: device is in reset!\n", __func__); + dev_dbg_ratelimited(dev, "%s: device is in reset\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; case STATE_FAILTERM: - dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__); + dev_dbg_ratelimited(dev, "%s: device has failed\n", __func__); scp->result = (DID_NO_CONNECT << 16); scp->scsi_done(scp); rc = 0; @@ -502,7 +503,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) if (likely(sg)) { nseg = scsi_dma_map(scp); if (unlikely(nseg < 0)) { - dev_err(dev, "%s: Fail DMA map!\n", __func__); + dev_err(dev, "%s: Fail DMA map\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } @@ -531,7 +532,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) out: if (kref_got) kref_put(&afu->mapcount, afu_unmap); - pr_devel("%s: returning rc=%d\n", __func__, rc); return rc; } @@ -651,6 +651,8 @@ static void term_mc(struct cxlflash_cfg *cfg) */ static void term_afu(struct cxlflash_cfg *cfg) { + struct device *dev = &cfg->dev->dev; + /* * Tear down is carefully orchestrated to ensure * no interrupts can come in when the problem state @@ -666,7 +668,7 @@ static void term_afu(struct cxlflash_cfg *cfg) term_mc(cfg); - pr_debug("%s: returning\n", __func__); + dev_dbg(dev, "%s: returning\n", __func__); } /** @@ -693,8 +695,7 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) return; if (!afu || !afu->afu_map) { - dev_dbg(dev, "%s: The problem state area is not mapped\n", - __func__); + dev_dbg(dev, "%s: Problem state area not mapped\n", __func__); return; } @@ -736,10 +737,11 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) static void cxlflash_remove(struct pci_dev *pdev) { struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); + struct device *dev = &pdev->dev; ulong lock_flags; if (!pci_is_enabled(pdev)) { - pr_debug("%s: Device is disabled\n", __func__); + dev_dbg(dev, "%s: Device is disabled\n", __func__); return; } @@ -775,7 +777,7 @@ static void cxlflash_remove(struct pci_dev *pdev) break; } - pr_debug("%s: returning\n", __func__); + dev_dbg(dev, "%s: returning\n", __func__); } /** @@ -817,6 +819,7 @@ out: static int init_pci(struct cxlflash_cfg *cfg) { struct pci_dev *pdev = cfg->dev; + struct device *dev = &cfg->dev->dev; int rc = 0; rc = pci_enable_device(pdev); @@ -827,15 +830,14 @@ static int init_pci(struct cxlflash_cfg *cfg) } if (rc) { - dev_err(&pdev->dev, "%s: Cannot enable adapter\n", - __func__); + dev_err(dev, "%s: Cannot enable adapter\n", __func__); cxlflash_wait_for_pci_err_recovery(cfg); goto out; } } out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -848,19 +850,19 @@ out: static int init_scsi(struct cxlflash_cfg *cfg) { struct pci_dev *pdev = cfg->dev; + struct device *dev = &cfg->dev->dev; int rc = 0; rc = scsi_add_host(cfg->host, &pdev->dev); if (rc) { - dev_err(&pdev->dev, "%s: scsi_add_host failed (rc=%d)\n", - __func__, rc); + dev_err(dev, "%s: scsi_add_host failed rc=%d\n", __func__, rc); goto out; } scsi_scan_host(cfg->host); out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -910,16 +912,12 @@ static void set_port_offline(__be64 __iomem *fc_regs) * Return: * TRUE (1) when the specified port is online * FALSE (0) when the specified port fails to come online after timeout - * -EINVAL when @delay_us is less than 1000 */ -static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) +static bool wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) { u64 status; - if (delay_us < 1000) { - pr_err("%s: invalid delay specified %d\n", __func__, delay_us); - return -EINVAL; - } + WARN_ON(delay_us < 1000); do { msleep(delay_us / 1000); @@ -943,16 +941,12 @@ static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) * Return: * TRUE (1) when the specified port is offline * FALSE (0) when the specified port fails to go offline after timeout - * -EINVAL when @delay_us is less than 1000 */ -static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) +static bool wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) { u64 status; - if (delay_us < 1000) { - pr_err("%s: invalid delay specified %d\n", __func__, delay_us); - return -EINVAL; - } + WARN_ON(delay_us < 1000); do { msleep(delay_us / 1000); @@ -981,11 +975,14 @@ static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, u64 wwpn) { + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; + set_port_offline(fc_regs); if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) { - pr_debug("%s: wait on port %d to go offline timed out\n", - __func__, port); + dev_dbg(dev, "%s: wait on port %d to go offline timed out\n", + __func__, port); } writeq_be(wwpn, &fc_regs[FC_PNAME / 8]); @@ -993,8 +990,8 @@ static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, set_port_online(fc_regs); if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) { - pr_debug("%s: wait on port %d to go online timed out\n", - __func__, port); + dev_dbg(dev, "%s: wait on port %d to go online timed out\n", + __func__, port); } } @@ -1013,6 +1010,8 @@ static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, */ static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) { + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; u64 port_sel; /* first switch the AFU to the other links, if any */ @@ -1024,21 +1023,21 @@ static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) set_port_offline(fc_regs); if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) - pr_err("%s: wait on port %d to go offline timed out\n", - __func__, port); + dev_err(dev, "%s: wait on port %d to go offline timed out\n", + __func__, port); set_port_online(fc_regs); if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) - pr_err("%s: wait on port %d to go online timed out\n", - __func__, port); + dev_err(dev, "%s: wait on port %d to go online timed out\n", + __func__, port); /* switch back to include this port */ port_sel |= (1ULL << port); writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); - pr_debug("%s: returning port_sel=%lld\n", __func__, port_sel); + dev_dbg(dev, "%s: returning port_sel=%016llx\n", __func__, port_sel); } /* @@ -1148,6 +1147,8 @@ static void afu_err_intr_init(struct afu *afu) static irqreturn_t cxlflash_sync_err_irq(int irq, void *data) { struct afu *afu = (struct afu *)data; + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; u64 reg; u64 reg_unmasked; @@ -1155,18 +1156,17 @@ static irqreturn_t cxlflash_sync_err_irq(int irq, void *data) reg_unmasked = (reg & SISL_ISTATUS_UNMASK); if (reg_unmasked == 0UL) { - pr_err("%s: %llX: spurious interrupt, intr_status %016llX\n", - __func__, (u64)afu, reg); + dev_err(dev, "%s: spurious interrupt, intr_status=%016llx\n", + __func__, reg); goto cxlflash_sync_err_irq_exit; } - pr_err("%s: %llX: unexpected interrupt, intr_status %016llX\n", - __func__, (u64)afu, reg); + dev_err(dev, "%s: unexpected interrupt, intr_status=%016llx\n", + __func__, reg); writeq_be(reg_unmasked, &afu->host_map->intr_clear); cxlflash_sync_err_irq_exit: - pr_debug("%s: returning rc=%d\n", __func__, IRQ_HANDLED); return IRQ_HANDLED; } @@ -1248,7 +1248,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) reg_unmasked = (reg & SISL_ASTATUS_UNMASK); if (reg_unmasked == 0) { - dev_err(dev, "%s: spurious interrupt, aintr_status 0x%016llX\n", + dev_err(dev, "%s: spurious interrupt, aintr_status=%016llx\n", __func__, reg); goto out; } @@ -1264,7 +1264,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) port = info->port; - dev_err(dev, "%s: FC Port %d -> %s, fc_status 0x%08llX\n", + dev_err(dev, "%s: FC Port %d -> %s, fc_status=%016llx\n", __func__, port, info->desc, readq_be(&global->fc_regs[port][FC_STATUS / 8])); @@ -1289,7 +1289,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) * should be the same and tracing one is sufficient. */ - dev_err(dev, "%s: fc %d: clearing fc_error 0x%08llX\n", + dev_err(dev, "%s: fc %d: clearing fc_error=%016llx\n", __func__, port, reg); writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]); @@ -1304,7 +1304,6 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) } out: - dev_dbg(dev, "%s: returning IRQ_HANDLED, afu=%p\n", __func__, afu); return IRQ_HANDLED; } @@ -1316,13 +1315,14 @@ out: */ static int start_context(struct cxlflash_cfg *cfg) { + struct device *dev = &cfg->dev->dev; int rc = 0; rc = cxl_start_context(cfg->mcctx, cfg->afu->work.work_element_descriptor, NULL); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1335,7 +1335,8 @@ static int start_context(struct cxlflash_cfg *cfg) */ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) { - struct pci_dev *dev = cfg->dev; + struct device *dev = &cfg->dev->dev; + struct pci_dev *pdev = cfg->dev; int rc = 0; int ro_start, ro_size, i, j, k; ssize_t vpd_size; @@ -1344,10 +1345,10 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" }; /* Get the VPD data from the device */ - vpd_size = cxl_read_adapter_vpd(dev, vpd_data, sizeof(vpd_data)); + vpd_size = cxl_read_adapter_vpd(pdev, vpd_data, sizeof(vpd_data)); if (unlikely(vpd_size <= 0)) { - dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n", - __func__, vpd_size); + dev_err(dev, "%s: Unable to read VPD (size = %ld)\n", + __func__, vpd_size); rc = -ENODEV; goto out; } @@ -1356,8 +1357,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) ro_start = pci_vpd_find_tag(vpd_data, 0, vpd_size, PCI_VPD_LRDT_RO_DATA); if (unlikely(ro_start < 0)) { - dev_err(&dev->dev, "%s: VPD Read-only data not found\n", - __func__); + dev_err(dev, "%s: VPD Read-only data not found\n", __func__); rc = -ENODEV; goto out; } @@ -1367,8 +1367,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) j = ro_size; i = ro_start + PCI_VPD_LRDT_TAG_SIZE; if (unlikely((i + j) > vpd_size)) { - pr_debug("%s: Might need to read more VPD (%d > %ld)\n", - __func__, (i + j), vpd_size); + dev_dbg(dev, "%s: Might need to read more VPD (%d > %ld)\n", + __func__, (i + j), vpd_size); ro_size = vpd_size - i; } @@ -1386,8 +1386,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) i = pci_vpd_find_info_keyword(vpd_data, i, j, wwpn_vpd_tags[k]); if (unlikely(i < 0)) { - dev_err(&dev->dev, "%s: Port %d WWPN not found " - "in VPD\n", __func__, k); + dev_err(dev, "%s: Port %d WWPN not found in VPD\n", + __func__, k); rc = -ENODEV; goto out; } @@ -1395,9 +1395,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) j = pci_vpd_info_field_size(&vpd_data[i]); i += PCI_VPD_INFO_FLD_HDR_SIZE; if (unlikely((i + j > vpd_size) || (j != WWPN_LEN))) { - dev_err(&dev->dev, "%s: Port %d WWPN incomplete or " - "VPD corrupt\n", - __func__, k); + dev_err(dev, "%s: Port %d WWPN incomplete or bad VPD\n", + __func__, k); rc = -ENODEV; goto out; } @@ -1405,15 +1404,15 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) memcpy(tmp_buf, &vpd_data[i], WWPN_LEN); rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]); if (unlikely(rc)) { - dev_err(&dev->dev, "%s: Fail to convert port %d WWPN " - "to integer\n", __func__, k); + dev_err(dev, "%s: WWPN conversion failed for port %d\n", + __func__, k); rc = -ENODEV; goto out; } } out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1467,7 +1466,8 @@ static int init_global(struct cxlflash_cfg *cfg) goto out; } - pr_debug("%s: wwpn0=0x%llX wwpn1=0x%llX\n", __func__, wwpn[0], wwpn[1]); + dev_dbg(dev, "%s: wwpn0=%016llx wwpn1=%016llx\n", + __func__, wwpn[0], wwpn[1]); /* Set up RRQ and SQ in AFU for master issued cmds */ writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start); @@ -1527,7 +1527,6 @@ static int init_global(struct cxlflash_cfg *cfg) &afu->ctrl_map->ctx_cap); /* Initialize heartbeat */ afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb); - out: return rc; } @@ -1539,6 +1538,7 @@ out: static int start_afu(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; int rc = 0; init_pcr(cfg); @@ -1565,7 +1565,7 @@ static int start_afu(struct cxlflash_cfg *cfg) rc = init_global(cfg); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1585,7 +1585,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, rc = cxl_allocate_afu_irqs(ctx, 3); if (unlikely(rc)) { - dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n", + dev_err(dev, "%s: allocate_afu_irqs failed rc=%d\n", __func__, rc); level = UNDO_NOOP; goto out; @@ -1594,8 +1594,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, rc = cxl_map_afu_irq(ctx, 1, cxlflash_sync_err_irq, afu, "SISL_MSI_SYNC_ERROR"); if (unlikely(rc <= 0)) { - dev_err(dev, "%s: IRQ 1 (SISL_MSI_SYNC_ERROR) map failed!\n", - __func__); + dev_err(dev, "%s: SISL_MSI_SYNC_ERROR map failed\n", __func__); level = FREE_IRQ; goto out; } @@ -1603,8 +1602,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, rc = cxl_map_afu_irq(ctx, 2, cxlflash_rrq_irq, afu, "SISL_MSI_RRQ_UPDATED"); if (unlikely(rc <= 0)) { - dev_err(dev, "%s: IRQ 2 (SISL_MSI_RRQ_UPDATED) map failed!\n", - __func__); + dev_err(dev, "%s: SISL_MSI_RRQ_UPDATED map failed\n", __func__); level = UNMAP_ONE; goto out; } @@ -1612,8 +1610,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, rc = cxl_map_afu_irq(ctx, 3, cxlflash_async_err_irq, afu, "SISL_MSI_ASYNC_ERROR"); if (unlikely(rc <= 0)) { - dev_err(dev, "%s: IRQ 3 (SISL_MSI_ASYNC_ERROR) map failed!\n", - __func__); + dev_err(dev, "%s: SISL_MSI_ASYNC_ERROR map failed\n", __func__); level = UNMAP_TWO; goto out; } @@ -1647,15 +1644,13 @@ static int init_mc(struct cxlflash_cfg *cfg) /* During initialization reset the AFU to start from a clean slate */ rc = cxl_afu_reset(cfg->mcctx); if (unlikely(rc)) { - dev_err(dev, "%s: initial AFU reset failed rc=%d\n", - __func__, rc); + dev_err(dev, "%s: AFU reset failed rc=%d\n", __func__, rc); goto ret; } level = init_intr(cfg, ctx); if (unlikely(level)) { - dev_err(dev, "%s: setting up interrupts failed rc=%d\n", - __func__, rc); + dev_err(dev, "%s: interrupt init failed rc=%d\n", __func__, rc); goto out; } @@ -1670,7 +1665,7 @@ static int init_mc(struct cxlflash_cfg *cfg) goto out; } ret: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; out: term_intr(cfg, level); @@ -1697,7 +1692,7 @@ static int init_afu(struct cxlflash_cfg *cfg) rc = init_mc(cfg); if (rc) { - dev_err(dev, "%s: call to init_mc failed, rc=%d!\n", + dev_err(dev, "%s: init_mc failed rc=%d\n", __func__, rc); goto out; } @@ -1705,7 +1700,7 @@ static int init_afu(struct cxlflash_cfg *cfg) /* Map the entire MMIO space of the AFU */ afu->afu_map = cxl_psa_map(cfg->mcctx); if (!afu->afu_map) { - dev_err(dev, "%s: call to cxl_psa_map failed!\n", __func__); + dev_err(dev, "%s: cxl_psa_map failed\n", __func__); rc = -ENOMEM; goto err1; } @@ -1717,8 +1712,8 @@ static int init_afu(struct cxlflash_cfg *cfg) afu->interface_version = readq_be(&afu->afu_map->global.regs.interface_version); if ((afu->interface_version + 1) == 0) { - pr_err("Back level AFU, please upgrade. AFU version %s " - "interface version 0x%llx\n", afu->version, + dev_err(dev, "Back level AFU, please upgrade. AFU version %s " + "interface version %016llx\n", afu->version, afu->interface_version); rc = -EINVAL; goto err2; @@ -1732,13 +1727,12 @@ static int init_afu(struct cxlflash_cfg *cfg) afu->context_reset = context_reset_ioarrin; } - pr_debug("%s: afu version %s, interface version 0x%llX\n", __func__, - afu->version, afu->interface_version); + dev_dbg(dev, "%s: afu_ver=%s interface_ver=%016llx\n", __func__, + afu->version, afu->interface_version); rc = start_afu(cfg); if (rc) { - dev_err(dev, "%s: call to start_afu failed, rc=%d!\n", - __func__, rc); + dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc); goto err2; } @@ -1749,7 +1743,7 @@ static int init_afu(struct cxlflash_cfg *cfg) /* Restore the LUN mappings */ cxlflash_restore_luntable(cfg); out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; err2: @@ -1793,7 +1787,8 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, static DEFINE_MUTEX(sync_active); if (cfg->state != STATE_NORMAL) { - pr_debug("%s: Sync not required! (%u)\n", __func__, cfg->state); + dev_dbg(dev, "%s: Sync not required state=%u\n", + __func__, cfg->state); return 0; } @@ -1810,7 +1805,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, init_completion(&cmd->cevent); cmd->parent = afu; - pr_debug("%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u); + dev_dbg(dev, "%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u); cmd->rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD; cmd->rcb.ctx_id = afu->ctx_hndl; @@ -1835,7 +1830,7 @@ out: atomic_dec(&afu->cmds_active); mutex_unlock(&sync_active); kfree(buf); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1847,16 +1842,17 @@ out: */ static int afu_reset(struct cxlflash_cfg *cfg) { + struct device *dev = &cfg->dev->dev; int rc = 0; + /* Stop the context before the reset. Since the context is * no longer available restart it after the reset is complete */ - term_afu(cfg); rc = init_afu(cfg); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1885,18 +1881,18 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) { int rc = SUCCESS; struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(host); + struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; int rcr = 0; - pr_debug("%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no, + scp->device->channel, scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); retry: switch (cfg->state) { @@ -1913,7 +1909,7 @@ retry: break; } - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1935,16 +1931,16 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) int rc = SUCCESS; int rcr = 0; struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(host); + struct device *dev = &cfg->dev->dev; - pr_debug("%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no, + scp->device->channel, scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); switch (cfg->state) { case STATE_NORMAL: @@ -1970,7 +1966,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) break; } - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -2036,8 +2032,7 @@ static ssize_t port0_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return cxlflash_show_port_status(0, afu, buf); @@ -2055,8 +2050,7 @@ static ssize_t port1_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return cxlflash_show_port_status(1, afu, buf); @@ -2073,8 +2067,7 @@ static ssize_t port1_show(struct device *dev, static ssize_t lun_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return scnprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); @@ -2107,7 +2100,7 @@ static ssize_t lun_mode_store(struct device *dev, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(shost); struct afu *afu = cfg->afu; int rc; u32 lun_mode; @@ -2169,7 +2162,7 @@ static ssize_t cxlflash_show_port_lun_table(u32 port, for (i = 0; i < CXLFLASH_NUM_VLUNS; i++) bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, - "%03d: %016llX\n", i, readq_be(&fc_port[i])); + "%03d: %016llx\n", i, readq_be(&fc_port[i])); return bytes; } @@ -2185,8 +2178,7 @@ static ssize_t port0_lun_table_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return cxlflash_show_port_lun_table(0, afu, buf); @@ -2204,8 +2196,7 @@ static ssize_t port1_lun_table_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return cxlflash_show_port_lun_table(1, afu, buf); @@ -2365,6 +2356,7 @@ static int cxlflash_probe(struct pci_dev *pdev, { struct Scsi_Host *host; struct cxlflash_cfg *cfg = NULL; + struct device *dev = &pdev->dev; struct dev_dependent_vals *ddv; int rc = 0; @@ -2376,8 +2368,7 @@ static int cxlflash_probe(struct pci_dev *pdev, host = scsi_host_alloc(&driver_template, sizeof(struct cxlflash_cfg)); if (!host) { - dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n", - __func__); + dev_err(dev, "%s: scsi_host_alloc failed\n", __func__); rc = -ENOMEM; goto out; } @@ -2388,12 +2379,11 @@ static int cxlflash_probe(struct pci_dev *pdev, host->unique_id = host->host_no; host->max_cmd_len = CXLFLASH_MAX_CDB_LEN; - cfg = (struct cxlflash_cfg *)host->hostdata; + cfg = shost_priv(host); cfg->host = host; rc = alloc_mem(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to alloc_mem failed!\n", - __func__); + dev_err(dev, "%s: alloc_mem failed\n", __func__); rc = -ENOMEM; scsi_host_put(cfg->host); goto out; @@ -2434,30 +2424,27 @@ static int cxlflash_probe(struct pci_dev *pdev, rc = init_pci(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to init_pci " - "failed rc=%d!\n", __func__, rc); + dev_err(dev, "%s: init_pci failed rc=%d\n", __func__, rc); goto out_remove; } cfg->init_state = INIT_STATE_PCI; rc = init_afu(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to init_afu " - "failed rc=%d!\n", __func__, rc); + dev_err(dev, "%s: init_afu failed rc=%d\n", __func__, rc); goto out_remove; } cfg->init_state = INIT_STATE_AFU; rc = init_scsi(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to init_scsi " - "failed rc=%d!\n", __func__, rc); + dev_err(dev, "%s: init_scsi failed rc=%d\n", __func__, rc); goto out_remove; } cfg->init_state = INIT_STATE_SCSI; out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; out_remove: @@ -2495,7 +2482,7 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, drain_ioctls(cfg); rc = cxlflash_mark_contexts_error(cfg); if (unlikely(rc)) - dev_err(dev, "%s: Failed to mark user contexts!(%d)\n", + dev_err(dev, "%s: Failed to mark user contexts rc=%d\n", __func__, rc); term_afu(cfg); return PCI_ERS_RESULT_NEED_RESET; @@ -2529,7 +2516,7 @@ static pci_ers_result_t cxlflash_pci_slot_reset(struct pci_dev *pdev) rc = init_afu(cfg); if (unlikely(rc)) { - dev_err(dev, "%s: EEH recovery failed! (%d)\n", __func__, rc); + dev_err(dev, "%s: EEH recovery failed rc=%d\n", __func__, rc); return PCI_ERS_RESULT_DISCONNECT; } @@ -2577,8 +2564,6 @@ static struct pci_driver cxlflash_driver = { */ static int __init init_cxlflash(void) { - pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME); - cxlflash_list_init(); return pci_register_driver(&cxlflash_driver); diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 42674ae6f4dd..90869cee2b20 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -212,7 +212,7 @@ struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid, } out: - dev_dbg(dev, "%s: rctxid=%016llX ctxinfo=%p ctxpid=%u pid=%u " + dev_dbg(dev, "%s: rctxid=%016llx ctxinfo=%p ctxpid=%u pid=%u " "ctx_ctrl=%u\n", __func__, rctxid, ctxi, ctxpid, pid, ctx_ctrl); @@ -260,7 +260,7 @@ static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) writeq_be(val, &ctrl_map->ctx_cap); val = readq_be(&ctrl_map->ctx_cap); if (val != (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD)) { - dev_err(dev, "%s: ctx may be closed val=%016llX\n", + dev_err(dev, "%s: ctx may be closed val=%016llx\n", __func__, val); rc = -EAGAIN; goto out; @@ -302,7 +302,7 @@ out: */ static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct glun_info *gli = lli->parent; u8 *cmd_buf = NULL; @@ -326,7 +326,7 @@ retry: scsi_cmd[1] = SAI_READ_CAPACITY_16; /* service action */ put_unaligned_be32(CMD_BUFSIZE, &scsi_cmd[10]); - dev_dbg(dev, "%s: %ssending cmd(0x%x)\n", __func__, + dev_dbg(dev, "%s: %ssending cmd(%02x)\n", __func__, retry_cnt ? "re" : "", scsi_cmd[0]); /* Drop the ioctl read semahpore across lengthy call */ @@ -336,7 +336,7 @@ retry: down_read(&cfg->ioctl_rwsem); rc = check_state(cfg); if (rc) { - dev_err(dev, "%s: Failed state! result=0x08%X\n", + dev_err(dev, "%s: Failed state result=%08x\n", __func__, result); rc = -ENODEV; goto out; @@ -378,7 +378,7 @@ retry: } if (result) { - dev_err(dev, "%s: command failed, result=0x%x\n", + dev_err(dev, "%s: command failed, result=%08x\n", __func__, result); rc = -EIO; goto out; @@ -415,29 +415,32 @@ out: struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, struct llun_info *lli) { + struct cxlflash_cfg *cfg = ctxi->cfg; + struct device *dev = &cfg->dev->dev; struct sisl_rht_entry *rhte = NULL; if (unlikely(!ctxi->rht_start)) { - pr_debug("%s: Context does not have allocated RHT!\n", + dev_dbg(dev, "%s: Context does not have allocated RHT\n", __func__); goto out; } if (unlikely(rhndl >= MAX_RHT_PER_CONTEXT)) { - pr_debug("%s: Bad resource handle! (%d)\n", __func__, rhndl); + dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", + __func__, rhndl); goto out; } if (unlikely(ctxi->rht_lun[rhndl] != lli)) { - pr_debug("%s: Bad resource handle LUN! (%d)\n", - __func__, rhndl); + dev_dbg(dev, "%s: Bad resource handle LUN rhndl=%d\n", + __func__, rhndl); goto out; } rhte = &ctxi->rht_start[rhndl]; if (unlikely(rhte->nmask == 0)) { - pr_debug("%s: Unopened resource handle! (%d)\n", - __func__, rhndl); + dev_dbg(dev, "%s: Unopened resource handle rhndl=%d\n", + __func__, rhndl); rhte = NULL; goto out; } @@ -456,6 +459,8 @@ out: struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, struct llun_info *lli) { + struct cxlflash_cfg *cfg = ctxi->cfg; + struct device *dev = &cfg->dev->dev; struct sisl_rht_entry *rhte = NULL; int i; @@ -470,7 +475,7 @@ struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, if (likely(rhte)) ctxi->rht_lun[i] = lli; - pr_debug("%s: returning rhte=%p (%d)\n", __func__, rhte, i); + dev_dbg(dev, "%s: returning rhte=%p index=%d\n", __func__, rhte, i); return rhte; } @@ -547,7 +552,7 @@ int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked) if (gli->mode == MODE_NONE) gli->mode = mode; else if (gli->mode != mode) { - pr_debug("%s: LUN operating in mode %d, requested mode %d\n", + pr_debug("%s: gli_mode=%d requested_mode=%d\n", __func__, gli->mode, mode); rc = -EINVAL; goto out; @@ -605,7 +610,7 @@ int _cxlflash_disk_release(struct scsi_device *sdev, struct ctx_info *ctxi, struct dk_cxlflash_release *release) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -622,13 +627,13 @@ int _cxlflash_disk_release(struct scsi_device *sdev, struct sisl_rht_entry *rhte; struct sisl_rht_entry_f1 *rhte_f1; - dev_dbg(dev, "%s: ctxid=%llu rhndl=0x%llx gli->mode=%u gli->users=%u\n", + dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu gli->mode=%u gli->users=%u\n", __func__, ctxid, release->rsrc_handle, gli->mode, gli->users); if (!ctxi) { ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto out; @@ -639,7 +644,7 @@ int _cxlflash_disk_release(struct scsi_device *sdev, rhte = get_rhte(ctxi, rhndl, lli); if (unlikely(!rhte)) { - dev_dbg(dev, "%s: Bad resource handle! (%d)\n", + dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", __func__, rhndl); rc = -EINVAL; goto out; @@ -758,13 +763,13 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg) lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL); ws = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*ws)), GFP_KERNEL); if (unlikely(!ctxi || !lli || !ws)) { - dev_err(dev, "%s: Unable to allocate context!\n", __func__); + dev_err(dev, "%s: Unable to allocate context\n", __func__); goto err; } rhte = (struct sisl_rht_entry *)get_zeroed_page(GFP_KERNEL); if (unlikely(!rhte)) { - dev_err(dev, "%s: Unable to allocate RHT!\n", __func__); + dev_err(dev, "%s: Unable to allocate RHT\n", __func__); goto err; } @@ -858,7 +863,7 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev, struct ctx_info *ctxi, struct dk_cxlflash_detach *detach) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct lun_access *lun_access, *t; @@ -875,7 +880,7 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev, if (!ctxi) { ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto out; @@ -964,7 +969,7 @@ static int cxlflash_cxl_release(struct inode *inode, struct file *file) ctxid = cxl_process_element(ctx); if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed! (%d)\n", + dev_err(dev, "%s: Context %p was closed ctxid=%d\n", __func__, ctx, ctxid); goto out; } @@ -973,18 +978,18 @@ static int cxlflash_cxl_release(struct inode *inode, struct file *file) if (unlikely(!ctxi)) { ctxi = get_context(cfg, ctxid, file, ctrl | CTX_CTRL_CLONE); if (!ctxi) { - dev_dbg(dev, "%s: Context %d already free!\n", + dev_dbg(dev, "%s: ctxid=%d already free\n", __func__, ctxid); goto out_release; } - dev_dbg(dev, "%s: Another process owns context %d!\n", + dev_dbg(dev, "%s: Another process owns ctxid=%d\n", __func__, ctxid); put_context(ctxi); goto out; } - dev_dbg(dev, "%s: close for context %d\n", __func__, ctxid); + dev_dbg(dev, "%s: close for ctxid=%d\n", __func__, ctxid); detach.context_id = ctxi->ctxid; list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) @@ -1011,17 +1016,20 @@ static void unmap_context(struct ctx_info *ctxi) /** * get_err_page() - obtains and allocates the error notification page + * @cfg: Internal structure associated with the host. * * Return: error notification page on success, NULL on failure */ -static struct page *get_err_page(void) +static struct page *get_err_page(struct cxlflash_cfg *cfg) { struct page *err_page = global.err_page; + struct device *dev = &cfg->dev->dev; if (unlikely(!err_page)) { err_page = alloc_page(GFP_KERNEL); if (unlikely(!err_page)) { - pr_err("%s: Unable to allocate err_page!\n", __func__); + dev_err(dev, "%s: Unable to allocate err_page\n", + __func__); goto out; } @@ -1039,7 +1047,7 @@ static struct page *get_err_page(void) } out: - pr_debug("%s: returning err_page=%p\n", __func__, err_page); + dev_dbg(dev, "%s: returning err_page=%p\n", __func__, err_page); return err_page; } @@ -1074,14 +1082,14 @@ static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ctxid = cxl_process_element(ctx); if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed! (%d)\n", + dev_err(dev, "%s: Context %p was closed ctxid=%d\n", __func__, ctx, ctxid); goto err; } ctxi = get_context(cfg, ctxid, file, ctrl); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid); goto err; } @@ -1091,13 +1099,12 @@ static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); rc = ctxi->cxl_mmap_vmops->fault(vma, vmf); } else { - dev_dbg(dev, "%s: err recovery active, use err_page!\n", + dev_dbg(dev, "%s: err recovery active, use err_page\n", __func__); - err_page = get_err_page(); + err_page = get_err_page(cfg); if (unlikely(!err_page)) { - dev_err(dev, "%s: Could not obtain error page!\n", - __func__); + dev_err(dev, "%s: Could not get err_page\n", __func__); rc = VM_FAULT_RETRY; goto out; } @@ -1147,7 +1154,7 @@ static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma) ctxid = cxl_process_element(ctx); if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed! (%d)\n", + dev_err(dev, "%s: Context %p was closed ctxid=%d\n", __func__, ctx, ctxid); rc = -EIO; goto out; @@ -1155,7 +1162,7 @@ static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma) ctxi = get_context(cfg, ctxid, file, ctrl); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid); rc = -EIO; goto out; } @@ -1251,7 +1258,7 @@ retry: break; goto retry; case STATE_FAILTERM: - dev_dbg(dev, "%s: Failed/Terminating!\n", __func__); + dev_dbg(dev, "%s: Failed/Terminating\n", __func__); rc = -ENODEV; break; default: @@ -1276,7 +1283,7 @@ retry: static int cxlflash_disk_attach(struct scsi_device *sdev, struct dk_cxlflash_attach *attach) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; struct llun_info *lli = sdev->hostdata; @@ -1303,24 +1310,24 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, } if (gli->max_lba == 0) { - dev_dbg(dev, "%s: No capacity info for this LUN (%016llX)\n", + dev_dbg(dev, "%s: No capacity info for LUN=%016llx\n", __func__, lli->lun_id[sdev->channel]); rc = read_cap16(sdev, lli); if (rc) { - dev_err(dev, "%s: Invalid device! (%d)\n", + dev_err(dev, "%s: Invalid device rc=%d\n", __func__, rc); rc = -ENODEV; goto out; } - dev_dbg(dev, "%s: LBA = %016llX\n", __func__, gli->max_lba); - dev_dbg(dev, "%s: BLK_LEN = %08X\n", __func__, gli->blk_len); + dev_dbg(dev, "%s: LBA = %016llx\n", __func__, gli->max_lba); + dev_dbg(dev, "%s: BLK_LEN = %08x\n", __func__, gli->blk_len); } if (attach->hdr.flags & DK_CXLFLASH_ATTACH_REUSE_CONTEXT) { rctxid = attach->context_id; ctxi = get_context(cfg, rctxid, NULL, 0); if (!ctxi) { - dev_dbg(dev, "%s: Bad context! (%016llX)\n", + dev_dbg(dev, "%s: Bad context rctxid=%016llx\n", __func__, rctxid); rc = -EINVAL; goto out; @@ -1328,7 +1335,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, list_for_each_entry(lun_access, &ctxi->luns, list) if (lun_access->lli == lli) { - dev_dbg(dev, "%s: Already attached!\n", + dev_dbg(dev, "%s: Already attached\n", __func__); rc = -EINVAL; goto out; @@ -1337,13 +1344,13 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, rc = scsi_device_get(sdev); if (unlikely(rc)) { - dev_err(dev, "%s: Unable to get sdev reference!\n", __func__); + dev_err(dev, "%s: Unable to get sdev reference\n", __func__); goto out; } lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL); if (unlikely(!lun_access)) { - dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__); + dev_err(dev, "%s: Unable to allocate lun_access\n", __func__); rc = -ENOMEM; goto err; } @@ -1353,7 +1360,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, /* Non-NULL context indicates reuse (another context reference) */ if (ctxi) { - dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n", + dev_dbg(dev, "%s: Reusing context for LUN rctxid=%016llx\n", __func__, rctxid); kref_get(&ctxi->kref); list_add(&lun_access->list, &ctxi->luns); @@ -1362,7 +1369,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, ctxi = create_context(cfg); if (unlikely(!ctxi)) { - dev_err(dev, "%s: Failed to create context! (%d)\n", + dev_err(dev, "%s: Failed to create context ctxid=%d\n", __func__, ctxid); goto err; } @@ -1388,7 +1395,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, ctxid = cxl_process_element(ctx); if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { - dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); + dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid); rc = -EPERM; goto err; } @@ -1522,7 +1529,7 @@ static int recover_context(struct cxlflash_cfg *cfg, ctxid = cxl_process_element(ctx); if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { - dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); + dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid); rc = -EPERM; goto err2; } @@ -1613,7 +1620,7 @@ err1: static int cxlflash_afu_recover(struct scsi_device *sdev, struct dk_cxlflash_recover_afu *recover) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct afu *afu = cfg->afu; @@ -1635,19 +1642,19 @@ static int cxlflash_afu_recover(struct scsi_device *sdev, goto out; rc = check_state(cfg); if (rc) { - dev_err(dev, "%s: Failed state! rc=%d\n", __func__, rc); + dev_err(dev, "%s: Failed state rc=%d\n", __func__, rc); rc = -ENODEV; goto out; } - dev_dbg(dev, "%s: reason 0x%016llX rctxid=%016llX\n", + dev_dbg(dev, "%s: reason=%016llx rctxid=%016llx\n", __func__, recover->reason, rctxid); retry: /* Ensure that this process is attached to the context */ ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto out; } @@ -1656,12 +1663,12 @@ retry: retry_recover: rc = recover_context(cfg, ctxi, &new_adap_fd); if (unlikely(rc)) { - dev_err(dev, "%s: Recovery failed for context %llu (rc=%d)\n", + dev_err(dev, "%s: Recovery failed ctxid=%llu rc=%d\n", __func__, ctxid, rc); if ((rc == -ENODEV) && ((atomic_read(&cfg->recovery_threads) > 1) || (lretry--))) { - dev_dbg(dev, "%s: Going to try again!\n", + dev_dbg(dev, "%s: Going to try again\n", __func__); mutex_unlock(mutex); msleep(100); @@ -1707,7 +1714,7 @@ retry_recover: goto retry; } - dev_dbg(dev, "%s: MMIO working, no recovery required!\n", __func__); + dev_dbg(dev, "%s: MMIO working, no recovery required\n", __func__); out: if (likely(ctxi)) put_context(ctxi); @@ -1726,7 +1733,7 @@ out: static int process_sense(struct scsi_device *sdev, struct dk_cxlflash_verify *verify) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -1737,7 +1744,7 @@ static int process_sense(struct scsi_device *sdev, rc = scsi_normalize_sense((const u8 *)&verify->sense_data, DK_CXLFLASH_VERIFY_SENSE_LEN, &sshdr); if (!rc) { - dev_err(dev, "%s: Failed to normalize sense data!\n", __func__); + dev_err(dev, "%s: Failed to normalize sense data\n", __func__); rc = -EINVAL; goto out; } @@ -1793,7 +1800,7 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, { int rc = 0; struct ctx_info *ctxi = NULL; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -1803,20 +1810,20 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, rctxid = verify->context_id; u64 last_lba = 0; - dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llX, hint=%016llX, " - "flags=%016llX\n", __func__, ctxid, verify->rsrc_handle, + dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llx, hint=%016llx, " + "flags=%016llx\n", __func__, ctxid, verify->rsrc_handle, verify->hint, verify->hdr.flags); ctxi = get_context(cfg, rctxid, lli, 0); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto out; } rhte = get_rhte(ctxi, rhndl, lli); if (unlikely(!rhte)) { - dev_dbg(dev, "%s: Bad resource handle! (%d)\n", + dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", __func__, rhndl); rc = -EINVAL; goto out; @@ -1863,7 +1870,7 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, out: if (likely(ctxi)) put_context(ctxi); - dev_dbg(dev, "%s: returning rc=%d llba=%llX\n", + dev_dbg(dev, "%s: returning rc=%d llba=%llx\n", __func__, rc, verify->last_lba); return rc; } @@ -1915,7 +1922,7 @@ static char *decode_ioctl(int cmd) */ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; struct llun_info *lli = sdev->hostdata; @@ -1935,25 +1942,25 @@ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) struct ctx_info *ctxi = NULL; struct sisl_rht_entry *rhte = NULL; - pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); rc = cxlflash_lun_attach(gli, MODE_PHYSICAL, false); if (unlikely(rc)) { - dev_dbg(dev, "%s: Failed to attach to LUN! (PHYSICAL)\n", - __func__); + dev_dbg(dev, "%s: Failed attach to LUN (PHYSICAL)\n", __func__); goto out; } ctxi = get_context(cfg, rctxid, lli, 0); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto err1; } rhte = rhte_checkout(ctxi, lli); if (unlikely(!rhte)) { - dev_dbg(dev, "%s: too many opens for this context\n", __func__); + dev_dbg(dev, "%s: Too many opens ctxid=%lld\n", + __func__, ctxid); rc = -EMFILE; /* too many opens */ goto err1; } @@ -1971,7 +1978,7 @@ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) out: if (likely(ctxi)) put_context(ctxi); - dev_dbg(dev, "%s: returning handle 0x%llx rc=%d llba %lld\n", + dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", __func__, rsrc_handle, rc, last_lba); return rc; @@ -1993,7 +2000,7 @@ err1: */ static int ioctl_common(struct scsi_device *sdev, int cmd) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; int rc = 0; @@ -2010,7 +2017,7 @@ static int ioctl_common(struct scsi_device *sdev, int cmd) case DK_CXLFLASH_VLUN_RESIZE: case DK_CXLFLASH_RELEASE: case DK_CXLFLASH_DETACH: - dev_dbg(dev, "%s: Command override! (%d)\n", + dev_dbg(dev, "%s: Command override rc=%d\n", __func__, rc); rc = 0; break; @@ -2040,7 +2047,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) { typedef int (*sioctl) (struct scsi_device *, void *); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; struct dk_cxlflash_hdr *hdr; @@ -2119,7 +2126,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) } if (unlikely(copy_from_user(&buf, arg, size))) { - dev_err(dev, "%s: copy_from_user() fail! " + dev_err(dev, "%s: copy_from_user() fail " "size=%lu cmd=%d (%s) arg=%p\n", __func__, size, cmd, decode_ioctl(cmd), arg); rc = -EFAULT; @@ -2135,7 +2142,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) } if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->rsvd[2] || hdr->return_flags) { - dev_dbg(dev, "%s: Reserved/rflags populated!\n", __func__); + dev_dbg(dev, "%s: Reserved/rflags populated\n", __func__); rc = -EINVAL; goto cxlflash_ioctl_exit; } @@ -2143,7 +2150,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) rc = do_ioctl(sdev, (void *)&buf); if (likely(!rc)) if (unlikely(copy_to_user(arg, &buf, size))) { - dev_err(dev, "%s: copy_to_user() fail! " + dev_err(dev, "%s: copy_to_user() fail " "size=%lu cmd=%d (%s) arg=%p\n", __func__, size, cmd, decode_ioctl(cmd), arg); rc = -EFAULT; diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 90c5d7f5278e..8fcc804dbef9 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -66,8 +66,8 @@ static int ba_init(struct ba_lun *ba_lun) int last_word_underflow = 0; u64 *lam; - pr_debug("%s: Initializing LUN: lun_id = %llX, " - "ba_lun->lsize = %lX, ba_lun->au_size = %lX\n", + pr_debug("%s: Initializing LUN: lun_id=%016llx " + "ba_lun->lsize=%lx ba_lun->au_size=%lX\n", __func__, ba_lun->lun_id, ba_lun->lsize, ba_lun->au_size); /* Calculate bit map size */ @@ -80,7 +80,7 @@ static int ba_init(struct ba_lun *ba_lun) /* Allocate lun information container */ bali = kzalloc(sizeof(struct ba_lun_info), GFP_KERNEL); if (unlikely(!bali)) { - pr_err("%s: Failed to allocate lun_info for lun_id %llX\n", + pr_err("%s: Failed to allocate lun_info lun_id=%016llx\n", __func__, ba_lun->lun_id); return -ENOMEM; } @@ -96,7 +96,7 @@ static int ba_init(struct ba_lun *ba_lun) GFP_KERNEL); if (unlikely(!bali->lun_alloc_map)) { pr_err("%s: Failed to allocate lun allocation map: " - "lun_id = %llX\n", __func__, ba_lun->lun_id); + "lun_id=%016llx\n", __func__, ba_lun->lun_id); kfree(bali); return -ENOMEM; } @@ -125,7 +125,7 @@ static int ba_init(struct ba_lun *ba_lun) bali->aun_clone_map = kzalloc((bali->total_aus * sizeof(u8)), GFP_KERNEL); if (unlikely(!bali->aun_clone_map)) { - pr_err("%s: Failed to allocate clone map: lun_id = %llX\n", + pr_err("%s: Failed to allocate clone map: lun_id=%016llx\n", __func__, ba_lun->lun_id); kfree(bali->lun_alloc_map); kfree(bali); @@ -136,7 +136,7 @@ static int ba_init(struct ba_lun *ba_lun) ba_lun->ba_lun_handle = bali; pr_debug("%s: Successfully initialized the LUN: " - "lun_id = %llX, bitmap size = %X, free_aun_cnt = %llX\n", + "lun_id=%016llx bitmap size=%x, free_aun_cnt=%llx\n", __func__, ba_lun->lun_id, bali->lun_bmap_size, bali->free_aun_cnt); return 0; @@ -165,10 +165,9 @@ static int find_free_range(u32 low, num_bits = (sizeof(*lam) * BITS_PER_BYTE); bit_pos = find_first_bit(lam, num_bits); - pr_devel("%s: Found free bit %llX in LUN " - "map entry %llX at bitmap index = %X\n", - __func__, bit_pos, bali->lun_alloc_map[i], - i); + pr_devel("%s: Found free bit %llu in LUN " + "map entry %016llx at bitmap index = %d\n", + __func__, bit_pos, bali->lun_alloc_map[i], i); *bit_word = i; bali->free_aun_cnt--; @@ -194,11 +193,11 @@ static u64 ba_alloc(struct ba_lun *ba_lun) bali = ba_lun->ba_lun_handle; pr_debug("%s: Received block allocation request: " - "lun_id = %llX, free_aun_cnt = %llX\n", + "lun_id=%016llx free_aun_cnt=%llx\n", __func__, ba_lun->lun_id, bali->free_aun_cnt); if (bali->free_aun_cnt == 0) { - pr_debug("%s: No space left on LUN: lun_id = %llX\n", + pr_debug("%s: No space left on LUN: lun_id=%016llx\n", __func__, ba_lun->lun_id); return -1ULL; } @@ -212,7 +211,7 @@ static u64 ba_alloc(struct ba_lun *ba_lun) bali, &bit_word); if (bit_pos == -1) { pr_debug("%s: Could not find an allocation unit on LUN:" - " lun_id = %llX\n", __func__, ba_lun->lun_id); + " lun_id=%016llx\n", __func__, ba_lun->lun_id); return -1ULL; } } @@ -223,8 +222,8 @@ static u64 ba_alloc(struct ba_lun *ba_lun) else bali->free_curr_idx = bit_word; - pr_debug("%s: Allocating AU number %llX, on lun_id %llX, " - "free_aun_cnt = %llX\n", __func__, + pr_debug("%s: Allocating AU number=%llx lun_id=%016llx " + "free_aun_cnt=%llx\n", __func__, ((bit_word * BITS_PER_LONG) + bit_pos), ba_lun->lun_id, bali->free_aun_cnt); @@ -266,18 +265,18 @@ static int ba_free(struct ba_lun *ba_lun, u64 to_free) bali = ba_lun->ba_lun_handle; if (validate_alloc(bali, to_free)) { - pr_debug("%s: The AUN %llX is not allocated on lun_id %llX\n", + pr_debug("%s: AUN %llx is not allocated on lun_id=%016llx\n", __func__, to_free, ba_lun->lun_id); return -1; } - pr_debug("%s: Received a request to free AU %llX on lun_id %llX, " - "free_aun_cnt = %llX\n", __func__, to_free, ba_lun->lun_id, + pr_debug("%s: Received a request to free AU=%llx lun_id=%016llx " + "free_aun_cnt=%llx\n", __func__, to_free, ba_lun->lun_id, bali->free_aun_cnt); if (bali->aun_clone_map[to_free] > 0) { - pr_debug("%s: AUN %llX on lun_id %llX has been cloned. Clone " - "count = %X\n", __func__, to_free, ba_lun->lun_id, + pr_debug("%s: AUN %llx lun_id=%016llx cloned. Clone count=%x\n", + __func__, to_free, ba_lun->lun_id, bali->aun_clone_map[to_free]); bali->aun_clone_map[to_free]--; return 0; @@ -294,8 +293,8 @@ static int ba_free(struct ba_lun *ba_lun, u64 to_free) else if (idx > bali->free_high_idx) bali->free_high_idx = idx; - pr_debug("%s: Successfully freed AU at bit_pos %X, bit map index %X on " - "lun_id %llX, free_aun_cnt = %llX\n", __func__, bit_pos, idx, + pr_debug("%s: Successfully freed AU bit_pos=%x bit map index=%x " + "lun_id=%016llx free_aun_cnt=%llx\n", __func__, bit_pos, idx, ba_lun->lun_id, bali->free_aun_cnt); return 0; @@ -313,16 +312,16 @@ static int ba_clone(struct ba_lun *ba_lun, u64 to_clone) struct ba_lun_info *bali = ba_lun->ba_lun_handle; if (validate_alloc(bali, to_clone)) { - pr_debug("%s: AUN %llX is not allocated on lun_id %llX\n", + pr_debug("%s: AUN=%llx not allocated on lun_id=%016llx\n", __func__, to_clone, ba_lun->lun_id); return -1; } - pr_debug("%s: Received a request to clone AUN %llX on lun_id %llX\n", + pr_debug("%s: Received a request to clone AUN %llx on lun_id=%016llx\n", __func__, to_clone, ba_lun->lun_id); if (bali->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) { - pr_debug("%s: AUN %llX on lun_id %llX hit max clones already\n", + pr_debug("%s: AUN %llx on lun_id=%016llx hit max clones already\n", __func__, to_clone, ba_lun->lun_id); return -1; } @@ -433,7 +432,7 @@ static int write_same16(struct scsi_device *sdev, u64 offset = lba; int left = nblks; u32 to = sdev->request_queue->rq_timeout; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); @@ -459,7 +458,7 @@ static int write_same16(struct scsi_device *sdev, down_read(&cfg->ioctl_rwsem); rc = check_state(cfg); if (rc) { - dev_err(dev, "%s: Failed state! result=0x08%X\n", + dev_err(dev, "%s: Failed state result=%08x\n", __func__, result); rc = -ENODEV; goto out; @@ -467,7 +466,7 @@ static int write_same16(struct scsi_device *sdev, if (result) { dev_err_ratelimited(dev, "%s: command failed for " - "offset %lld result=0x%x\n", + "offset=%lld result=%08x\n", __func__, offset, result); rc = -EIO; goto out; @@ -480,7 +479,7 @@ out: kfree(cmd_buf); kfree(scsi_cmd); kfree(sense_buf); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -508,6 +507,8 @@ static int grow_lxt(struct afu *afu, struct sisl_rht_entry *rhte, u64 *new_size) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct sisl_lxt_entry *lxt = NULL, *lxt_old = NULL; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -527,7 +528,8 @@ static int grow_lxt(struct afu *afu, mutex_lock(&blka->mutex); av_size = ba_space(&blka->ba_lun); if (unlikely(av_size <= 0)) { - pr_debug("%s: ba_space error: av_size %d\n", __func__, av_size); + dev_dbg(dev, "%s: ba_space error av_size=%d\n", + __func__, av_size); mutex_unlock(&blka->mutex); rc = -ENOSPC; goto out; @@ -568,8 +570,8 @@ static int grow_lxt(struct afu *afu, */ aun = ba_alloc(&blka->ba_lun); if ((aun == -1ULL) || (aun >= blka->nchunk)) - pr_debug("%s: ba_alloc error: allocated chunk# %llX, " - "max %llX\n", __func__, aun, blka->nchunk - 1); + dev_dbg(dev, "%s: ba_alloc error allocated chunk=%llu " + "max=%llu\n", __func__, aun, blka->nchunk - 1); /* select both ports, use r/w perms from RHT */ lxt[i].rlba_base = ((aun << MC_CHUNK_SHIFT) | @@ -599,7 +601,7 @@ static int grow_lxt(struct afu *afu, kfree(lxt_old); *new_size = my_new_size; out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -621,6 +623,8 @@ static int shrink_lxt(struct afu *afu, struct ctx_info *ctxi, u64 *new_size) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct sisl_lxt_entry *lxt, *lxt_old; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -706,7 +710,7 @@ static int shrink_lxt(struct afu *afu, kfree(lxt_old); *new_size = my_new_size; out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -728,7 +732,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, struct ctx_info *ctxi, struct dk_cxlflash_resize *resize) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; struct afu *afu = cfg->afu; @@ -751,13 +756,13 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len; new_size = DIV_ROUND_UP(nsectors, MC_CHUNK_SIZE); - pr_debug("%s: ctxid=%llu rhndl=0x%llx, req_size=0x%llx," - "new_size=%llx\n", __func__, ctxid, resize->rsrc_handle, - resize->req_size, new_size); + dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu req_size=%llu new_size=%llu\n", + __func__, ctxid, resize->rsrc_handle, resize->req_size, + new_size); if (unlikely(gli->mode != MODE_VIRTUAL)) { - pr_debug("%s: LUN mode does not support resize! (%d)\n", - __func__, gli->mode); + dev_dbg(dev, "%s: LUN mode does not support resize mode=%d\n", + __func__, gli->mode); rc = -EINVAL; goto out; @@ -766,7 +771,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, if (!ctxi) { ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); if (unlikely(!ctxi)) { - pr_debug("%s: Bad context! (%llu)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", + __func__, ctxid); rc = -EINVAL; goto out; } @@ -776,7 +782,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, rhte = get_rhte(ctxi, rhndl, lli); if (unlikely(!rhte)) { - pr_debug("%s: Bad resource handle! (%u)\n", __func__, rhndl); + dev_dbg(dev, "%s: Bad resource handle rhndl=%u\n", + __func__, rhndl); rc = -EINVAL; goto out; } @@ -794,8 +801,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, out: if (put_ctx) put_context(ctxi); - pr_debug("%s: resized to %lld returning rc=%d\n", - __func__, resize->last_lba, rc); + dev_dbg(dev, "%s: resized to %llu returning rc=%d\n", + __func__, resize->last_lba, rc); return rc; } @@ -815,6 +822,7 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) u32 chan; u32 lind; struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; struct sisl_global_map __iomem *agm = &afu->afu_map->global; mutex_lock(&global.mutex); @@ -828,15 +836,15 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) if (lli->port_sel == BOTH_PORTS) { writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); - pr_debug("%s: Virtual LUN on slot %d id0=%llx, " - "id1=%llx\n", __func__, lind, - lli->lun_id[0], lli->lun_id[1]); + dev_dbg(dev, "%s: Virtual LUN on slot %d id0=%llx " + "id1=%llx\n", __func__, lind, + lli->lun_id[0], lli->lun_id[1]); } else { chan = PORT2CHAN(lli->port_sel); writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); - pr_debug("%s: Virtual LUN on slot %d chan=%d, " - "id=%llx\n", __func__, lind, chan, - lli->lun_id[chan]); + dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d " + "id=%llx\n", __func__, lind, chan, + lli->lun_id[chan]); } } @@ -860,6 +868,7 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) u32 lind; int rc = 0; struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; struct sisl_global_map __iomem *agm = &afu->afu_map->global; mutex_lock(&global.mutex); @@ -882,8 +891,8 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); cfg->promote_lun_index++; - pr_debug("%s: Virtual LUN on slot %d id0=%llx, id1=%llx\n", - __func__, lind, lli->lun_id[0], lli->lun_id[1]); + dev_dbg(dev, "%s: Virtual LUN on slot %d id0=%llx id1=%llx\n", + __func__, lind, lli->lun_id[0], lli->lun_id[1]); } else { /* * If this LUN is visible only from one port, we will put @@ -898,14 +907,14 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) lind = lli->lun_index = cfg->last_lun_index[chan]; writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); cfg->last_lun_index[chan]--; - pr_debug("%s: Virtual LUN on slot %d chan=%d, id=%llx\n", - __func__, lind, chan, lli->lun_id[chan]); + dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d id=%llx\n", + __func__, lind, chan, lli->lun_id[chan]); } lli->in_table = true; out: mutex_unlock(&global.mutex); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -923,7 +932,7 @@ out: */ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -942,14 +951,14 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) struct ctx_info *ctxi = NULL; struct sisl_rht_entry *rhte = NULL; - pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); /* Setup the LUNs block allocator on first call */ mutex_lock(&gli->mutex); if (gli->mode == MODE_NONE) { rc = init_vlun(lli); if (rc) { - dev_err(dev, "%s: call to init_vlun failed rc=%d!\n", + dev_err(dev, "%s: init_vlun failed rc=%d\n", __func__, rc); rc = -ENOMEM; goto err0; @@ -958,29 +967,28 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) rc = cxlflash_lun_attach(gli, MODE_VIRTUAL, true); if (unlikely(rc)) { - dev_err(dev, "%s: Failed to attach to LUN! (VIRTUAL)\n", - __func__); + dev_err(dev, "%s: Failed attach to LUN (VIRTUAL)\n", __func__); goto err0; } mutex_unlock(&gli->mutex); rc = init_luntable(cfg, lli); if (rc) { - dev_err(dev, "%s: call to init_luntable failed rc=%d!\n", - __func__, rc); + dev_err(dev, "%s: init_luntable failed rc=%d\n", __func__, rc); goto err1; } ctxi = get_context(cfg, rctxid, lli, 0); if (unlikely(!ctxi)) { - dev_err(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + dev_err(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto err1; } rhte = rhte_checkout(ctxi, lli); if (unlikely(!rhte)) { - dev_err(dev, "%s: too many opens for this context\n", __func__); + dev_err(dev, "%s: too many opens ctxid=%llu\n", + __func__, ctxid); rc = -EMFILE; /* too many opens */ goto err1; } @@ -996,7 +1004,7 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) resize.rsrc_handle = rsrc_handle; rc = _cxlflash_vlun_resize(sdev, ctxi, &resize); if (rc) { - dev_err(dev, "%s: resize failed rc %d\n", __func__, rc); + dev_err(dev, "%s: resize failed rc=%d\n", __func__, rc); goto err2; } last_lba = resize.last_lba; @@ -1013,8 +1021,8 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) out: if (likely(ctxi)) put_context(ctxi); - pr_debug("%s: returning handle 0x%llx rc=%d llba %lld\n", - __func__, rsrc_handle, rc, last_lba); + dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", + __func__, rsrc_handle, rc, last_lba); return rc; err2: @@ -1047,6 +1055,8 @@ static int clone_lxt(struct afu *afu, struct sisl_rht_entry *rhte, struct sisl_rht_entry *rhte_src) { + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; struct sisl_lxt_entry *lxt; u32 ngrps; u64 aun; /* chunk# allocated by block allocator */ @@ -1101,7 +1111,7 @@ static int clone_lxt(struct afu *afu, cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); - pr_debug("%s: returning\n", __func__); + dev_dbg(dev, "%s: returning\n", __func__); return 0; } @@ -1120,7 +1130,8 @@ static int clone_lxt(struct afu *afu, int cxlflash_disk_clone(struct scsi_device *sdev, struct dk_cxlflash_clone *clone) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; struct blka *blka = &gli->blka; @@ -1140,8 +1151,8 @@ int cxlflash_disk_clone(struct scsi_device *sdev, bool found; LIST_HEAD(sidecar); - pr_debug("%s: ctxid_src=%llu ctxid_dst=%llu\n", - __func__, ctxid_src, ctxid_dst); + dev_dbg(dev, "%s: ctxid_src=%llu ctxid_dst=%llu\n", + __func__, ctxid_src, ctxid_dst); /* Do not clone yourself */ if (unlikely(rctxid_src == rctxid_dst)) { @@ -1151,16 +1162,16 @@ int cxlflash_disk_clone(struct scsi_device *sdev, if (unlikely(gli->mode != MODE_VIRTUAL)) { rc = -EINVAL; - pr_debug("%s: Clone not supported on physical LUNs! (%d)\n", - __func__, gli->mode); + dev_dbg(dev, "%s: Only supported on virtual LUNs mode=%u\n", + __func__, gli->mode); goto out; } ctxi_src = get_context(cfg, rctxid_src, lli, CTX_CTRL_CLONE); ctxi_dst = get_context(cfg, rctxid_dst, lli, 0); if (unlikely(!ctxi_src || !ctxi_dst)) { - pr_debug("%s: Bad context! (%llu,%llu)\n", __func__, - ctxid_src, ctxid_dst); + dev_dbg(dev, "%s: Bad context ctxid_src=%llu ctxid_dst=%llu\n", + __func__, ctxid_src, ctxid_dst); rc = -EINVAL; goto out; } @@ -1185,8 +1196,8 @@ int cxlflash_disk_clone(struct scsi_device *sdev, lun_access_dst = kzalloc(sizeof(*lun_access_dst), GFP_KERNEL); if (unlikely(!lun_access_dst)) { - pr_err("%s: Unable to allocate lun_access!\n", - __func__); + dev_err(dev, "%s: lun_access allocation fail\n", + __func__); rc = -ENOMEM; goto out; } @@ -1197,7 +1208,7 @@ int cxlflash_disk_clone(struct scsi_device *sdev, } if (unlikely(!ctxi_src->rht_out)) { - pr_debug("%s: Nothing to clone!\n", __func__); + dev_dbg(dev, "%s: Nothing to clone\n", __func__); goto out_success; } @@ -1256,7 +1267,7 @@ out: put_context(ctxi_src); if (ctxi_dst) put_context(ctxi_dst); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; err: From 0df5bef739601f18bffc0d256ae451f239a826bd Mon Sep 17 00:00:00 2001 From: Uma Krishnan Date: Wed, 11 Jan 2017 19:20:03 -0600 Subject: [PATCH 0359/1587] scsi: cxlflash: Cancel scheduled workers before stopping AFU When processing an AFU asynchronous interrupt, if the action results in an operation that requires off level processing (a link reset for example), the worker thread is scheduled. In the meantime a reset event (i.e.: EEH) could unmap the AFU to recover. This results in an Oops when the worker thread tries to access the AFU mapping. [c000000f17e03b90] d000000007cd5978 cxlflash_worker_thread+0x268/0x550 [c000000f17e03c40] c00000000011883c process_one_work+0x1dc/0x680 [c000000f17e03ce0] c000000000118e80 worker_thread+0x1a0/0x520 [c000000f17e03d80] c000000000126174 kthread+0xf4/0x100 [c000000f17e03e30] c00000000000a47c ret_from_kernel_thread+0x5c/0xe0 In an effort to avoid this, a mapcount was introduced in commit b45cdbaf9f7f ("cxlflash: Resolve oops in wait_port_offline") but due to the race condition described above, this solution is incomplete. In order to fully resolve this problem and to simplify things, this commit removes the mapcount solution. Instead, the scheduled worker thread is cancelled after interrupts have been disabled and prior to the mapping being freed. Fixes: b45cdbaf9f7f ("cxlflash: Resolve oops in wait_port_offline") Signed-off-by: Uma Krishnan Acked-by: Matthew R. Ochs Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 2 -- drivers/scsi/cxlflash/main.c | 34 ++++++---------------------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index dee865735ac0..d11dcc59ff46 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -174,8 +174,6 @@ struct afu { struct sisl_host_map __iomem *host_map; /* MC host map */ struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */ - struct kref mapcount; - ctx_hndl_t ctx_hndl; /* master's context handle */ atomic_t hsq_credits; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index ab38bca5df2b..7069639e92bc 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -419,16 +419,6 @@ out: return rc; } -static void afu_unmap(struct kref *ref) -{ - struct afu *afu = container_of(ref, struct afu, mapcount); - - if (likely(afu->afu_map)) { - cxl_psa_unmap((void __iomem *)afu->afu_map); - afu->afu_map = NULL; - } -} - /** * cxlflash_driver_info() - information handler for this host driver * @host: SCSI host associated with device. @@ -459,7 +449,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) ulong lock_flags; int nseg = 0; int rc = 0; - int kref_got = 0; dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " "cdb=(%08x-%08x-%08x-%08x)\n", @@ -497,9 +486,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) break; } - kref_get(&cfg->afu->mapcount); - kref_got = 1; - if (likely(sg)) { nseg = scsi_dma_map(scp); if (unlikely(nseg < 0)) { @@ -530,8 +516,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) if (unlikely(rc)) scsi_dma_unmap(scp); out: - if (kref_got) - kref_put(&afu->mapcount, afu_unmap); return rc; } @@ -569,13 +553,15 @@ static void free_mem(struct cxlflash_cfg *cfg) * * Safe to call with AFU in a partially allocated/initialized state. * - * Waits for any active internal AFU commands to timeout and then unmaps - * the MMIO space. + * Cancels scheduled worker threads, waits for any active internal AFU + * commands to timeout and then unmaps the MMIO space. */ static void stop_afu(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; + cancel_work_sync(&cfg->work_q); + if (likely(afu)) { while (atomic_read(&afu->cmds_active)) ssleep(1); @@ -583,7 +569,6 @@ static void stop_afu(struct cxlflash_cfg *cfg) cxl_psa_unmap((void __iomem *)afu->afu_map); afu->afu_map = NULL; } - kref_put(&afu->mapcount, afu_unmap); } } @@ -767,7 +752,6 @@ static void cxlflash_remove(struct pci_dev *pdev) scsi_remove_host(cfg->host); /* fall through */ case INIT_STATE_AFU: - cancel_work_sync(&cfg->work_q); term_afu(cfg); case INIT_STATE_PCI: pci_disable_device(pdev); @@ -1277,7 +1261,6 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) __func__, port); cfg->lr_state = LINK_RESET_REQUIRED; cfg->lr_port = port; - kref_get(&cfg->afu->mapcount); schedule_work(&cfg->work_q); } @@ -1298,7 +1281,6 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) if (info->action & SCAN_HOST) { atomic_inc(&cfg->scan_host_needed); - kref_get(&cfg->afu->mapcount); schedule_work(&cfg->work_q); } } @@ -1704,7 +1686,6 @@ static int init_afu(struct cxlflash_cfg *cfg) rc = -ENOMEM; goto err1; } - kref_init(&afu->mapcount); /* No byte reverse on reading afu_version or string will be backwards */ reg = readq(&afu->afu_map->global.regs.afu_version); @@ -1716,7 +1697,7 @@ static int init_afu(struct cxlflash_cfg *cfg) "interface version %016llx\n", afu->version, afu->interface_version); rc = -EINVAL; - goto err2; + goto err1; } if (afu_is_sq_cmd_mode(afu)) { @@ -1733,7 +1714,7 @@ static int init_afu(struct cxlflash_cfg *cfg) rc = start_afu(cfg); if (rc) { dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc); - goto err2; + goto err1; } afu_err_intr_init(cfg->afu); @@ -1746,8 +1727,6 @@ out: dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; -err2: - kref_put(&afu->mapcount, afu_unmap); err1: term_intr(cfg, UNMAP_THREE); term_mc(cfg); @@ -2341,7 +2320,6 @@ static void cxlflash_worker_thread(struct work_struct *work) if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0) scsi_scan_host(cfg->host); - kref_put(&afu->mapcount, afu_unmap); } /** From 1661f2e21c8bbf922dcb76faf2126a33ffe4cddb Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Wed, 4 Jan 2017 11:19:31 +0100 Subject: [PATCH 0360/1587] floppy: replace wrong kmalloc(GFP_USER) with GFP_KERNEL The raw_cmd_copyin() function does a kmalloc() with GFP_USER, although the allocated structure is obviously not mapped to userspace, just copied from/to. In this case GFP_KERNEL is more appropriate, so let's use it, although in the current implementation this does not manifest as any error. Reported-by: Matthew Wilcox Signed-off-by: Vlastimil Babka Signed-off-by: Jiri Kosina --- drivers/block/floppy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index a391a3cfb3fe..184887af4b9f 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3119,7 +3119,7 @@ static int raw_cmd_copyin(int cmd, void __user *param, *rcmd = NULL; loop: - ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER); + ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_KERNEL); if (!ptr) return -ENOMEM; *rcmd = ptr; From 729204ef49ec00b788ce23deb9eb922a5769f55d Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 17 Dec 2016 18:49:09 +0800 Subject: [PATCH 0361/1587] block: relax check on sg gap If the last bvec of the 1st bio and the 1st bvec of the next bio are physically contigious, and the latter can be merged to last segment of the 1st bio, we should think they don't violate sg gap(or virt boundary) limit. Both Vitaly and Dexuan reported lots of unmergeable small bios are observed when running mkfs on Hyper-V virtual storage, and performance becomes quite low. This patch fixes that performance issue. The same issue should exist on NVMe, since it sets virt boundary too. Reported-by: Vitaly Kuznetsov Reported-by: Dexuan Cui Tested-by: Dexuan Cui Cc: Keith Busch Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 83695641bd5e..b20da8dfa7ec 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1607,6 +1607,25 @@ static inline bool bvec_gap_to_prev(struct request_queue *q, return __bvec_gap_to_prev(q, bprv, offset); } +/* + * Check if the two bvecs from two bios can be merged to one segment. + * If yes, no need to check gap between the two bios since the 1st bio + * and the 1st bvec in the 2nd bio can be handled in one segment. + */ +static inline bool bios_segs_mergeable(struct request_queue *q, + struct bio *prev, struct bio_vec *prev_last_bv, + struct bio_vec *next_first_bv) +{ + if (!BIOVEC_PHYS_MERGEABLE(prev_last_bv, next_first_bv)) + return false; + if (!BIOVEC_SEG_BOUNDARY(q, prev_last_bv, next_first_bv)) + return false; + if (prev->bi_seg_back_size + next_first_bv->bv_len > + queue_max_segment_size(q)) + return false; + return true; +} + static inline bool bio_will_gap(struct request_queue *q, struct bio *prev, struct bio *next) { @@ -1616,7 +1635,8 @@ static inline bool bio_will_gap(struct request_queue *q, struct bio *prev, bio_get_last_bvec(prev, &pb); bio_get_first_bvec(next, &nb); - return __bvec_gap_to_prev(q, &pb, nb.bv_offset); + if (!bios_segs_mergeable(q, prev, &pb, &nb)) + return __bvec_gap_to_prev(q, &pb, nb.bv_offset); } return false; From f8a5b12247fe18f7fed801ad262a7ab190e1f848 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 13 Dec 2016 09:24:51 -0700 Subject: [PATCH 0362/1587] blk-mq: make mq_ops a const pointer We never change it, make that clear. Signed-off-by: Jens Axboe Reviewed-by: Bart Van Assche --- block/blk-mq.c | 2 +- include/linux/blk-mq.h | 2 +- include/linux/blkdev.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index a8e67a155d04..79e1cb0f7b15 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -639,7 +639,7 @@ struct blk_mq_timeout_data { void blk_mq_rq_timed_out(struct request *req, bool reserved) { - struct blk_mq_ops *ops = req->q->mq_ops; + const struct blk_mq_ops *ops = req->q->mq_ops; enum blk_eh_timer_return ret = BLK_EH_RESET_TIMER; /* diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 4a2ab5d99ff7..afc81d77e471 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -60,7 +60,7 @@ struct blk_mq_hw_ctx { struct blk_mq_tag_set { unsigned int *mq_map; - struct blk_mq_ops *ops; + const struct blk_mq_ops *ops; unsigned int nr_hw_queues; unsigned int queue_depth; /* max hw supported */ unsigned int reserved_tags; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index b20da8dfa7ec..2e99d659b0f1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -407,7 +407,7 @@ struct request_queue { dma_drain_needed_fn *dma_drain_needed; lld_busy_fn *lld_busy_fn; - struct blk_mq_ops *mq_ops; + const struct blk_mq_ops *mq_ops; unsigned int *mq_map; From 1e668f4e7921e8c82838cf5f95ff4a2d5c852efc Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 11 Jan 2017 15:41:40 -0500 Subject: [PATCH 0363/1587] MAINTAINERS: Update maintainer entry for NBD The old maintainers email is bouncing and I've rewritten most of this driver in the recent months. Also add linux-block to the mailinglist and remove the old tree, I will send patches through the linux-block tree. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Jens Axboe --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5f0420a0da5b..f481713fe44c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8599,10 +8599,10 @@ S: Maintained F: drivers/net/ethernet/netronome/ NETWORK BLOCK DEVICE (NBD) -M: Markus Pargmann +M: Josef Bacik S: Maintained +L: linux-block@vger.kernel.org L: nbd-general@lists.sourceforge.net -T: git git://git.pengutronix.de/git/mpa/linux-nbd.git F: Documentation/blockdev/nbd.txt F: drivers/block/nbd.c F: include/uapi/linux/nbd.h From 2c0f83f328fcb48da03401e1ecb2b34492671a9a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 11 Jan 2017 14:26:52 +0100 Subject: [PATCH 0364/1587] scsi: qla4xxx: remove two unused MSI-X related #defines Spotted while preparing qla2xxx changes as the symbols exist in both drivers (sigh..). Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_def.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index aeebefb1e9f8..fc233717355f 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -408,9 +408,6 @@ struct qla4_8xxx_legacy_intr_set { }; /* MSI-X Support */ - -#define QLA_MSIX_DEFAULT 0 -#define QLA_MSIX_RSP_Q 1 #define QLA_MSIX_ENTRIES 2 /* From b4ba35c75a0671a06b978b6386b54148efddf39f Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 11 Jan 2017 16:33:54 -0500 Subject: [PATCH 0365/1587] selinux: drop unused socket security classes Several of the extended socket classes introduced by commit da69a5306ab92e07 ("selinux: support distinctions among all network address families") are never used because sockets can never be created with the associated address family. Remove these unused socket security classes. The removed classes are bridge_socket for PF_BRIDGE, ib_socket for PF_IB, and mpls_socket for PF_MPLS. Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 6 ------ security/selinux/include/classmap.h | 6 ------ 2 files changed, 12 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index bada3cd42b9c..55ad878f1146 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1353,8 +1353,6 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc return SECCLASS_IPX_SOCKET; case PF_NETROM: return SECCLASS_NETROM_SOCKET; - case PF_BRIDGE: - return SECCLASS_BRIDGE_SOCKET; case PF_ATMPVC: return SECCLASS_ATMPVC_SOCKET; case PF_X25: @@ -1373,10 +1371,6 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc return SECCLASS_PPPOX_SOCKET; case PF_LLC: return SECCLASS_LLC_SOCKET; - case PF_IB: - return SECCLASS_IB_SOCKET; - case PF_MPLS: - return SECCLASS_MPLS_SOCKET; case PF_CAN: return SECCLASS_CAN_SOCKET; case PF_TIPC: diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 0dfd26d0b8d8..7898ffa6d3e6 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -183,8 +183,6 @@ struct security_class_mapping secclass_map[] = { { COMMON_SOCK_PERMS, NULL } }, { "netrom_socket", { COMMON_SOCK_PERMS, NULL } }, - { "bridge_socket", - { COMMON_SOCK_PERMS, NULL } }, { "atmpvc_socket", { COMMON_SOCK_PERMS, NULL } }, { "x25_socket", @@ -203,10 +201,6 @@ struct security_class_mapping secclass_map[] = { { COMMON_SOCK_PERMS, NULL } }, { "llc_socket", { COMMON_SOCK_PERMS, NULL } }, - { "ib_socket", - { COMMON_SOCK_PERMS, NULL } }, - { "mpls_socket", - { COMMON_SOCK_PERMS, NULL } }, { "can_socket", { COMMON_SOCK_PERMS, NULL } }, { "tipc_socket", From 3a2f5a59a695a73e0cde9a61e0feae5fa730e936 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 10 Jan 2017 12:28:32 -0500 Subject: [PATCH 0366/1587] security,selinux,smack: kill security_task_wait hook As reported by yangshukui, a permission denial from security_task_wait() can lead to a soft lockup in zap_pid_ns_processes() since it only expects sys_wait4() to return 0 or -ECHILD. Further, security_task_wait() can in general lead to zombies; in the absence of some way to automatically reparent a child process upon a denial, the hook is not useful. Remove the security hook and its implementations in SELinux and Smack. Smack already removed its check from its hook. Reported-by: yangshukui Signed-off-by: Stephen Smalley Acked-by: Casey Schaufler Acked-by: Oleg Nesterov Signed-off-by: Paul Moore --- include/linux/lsm_hooks.h | 7 ------- include/linux/security.h | 6 ------ kernel/exit.c | 19 ++----------------- security/security.c | 6 ------ security/selinux/hooks.c | 7 ------- security/smack/smack_lsm.c | 20 -------------------- 6 files changed, 2 insertions(+), 63 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 0dde95900196..6fe7a5cb0be1 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -666,11 +666,6 @@ * @sig contains the signal value. * @secid contains the sid of the process where the signal originated * Return 0 if permission is granted. - * @task_wait: - * Check permission before allowing a process to reap a child process @p - * and collect its status information. - * @p contains the task_struct for process. - * Return 0 if permission is granted. * @task_prctl: * Check permission before performing a process control operation on the * current process. @@ -1507,7 +1502,6 @@ union security_list_options { int (*task_movememory)(struct task_struct *p); int (*task_kill)(struct task_struct *p, struct siginfo *info, int sig, u32 secid); - int (*task_wait)(struct task_struct *p); int (*task_prctl)(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); void (*task_to_inode)(struct task_struct *p, struct inode *inode); @@ -1767,7 +1761,6 @@ struct security_hook_heads { struct list_head task_getscheduler; struct list_head task_movememory; struct list_head task_kill; - struct list_head task_wait; struct list_head task_prctl; struct list_head task_to_inode; struct list_head ipc_permission; diff --git a/include/linux/security.h b/include/linux/security.h index f4ebac117fa6..d3868f2ebada 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -332,7 +332,6 @@ int security_task_getscheduler(struct task_struct *p); int security_task_movememory(struct task_struct *p); int security_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid); -int security_task_wait(struct task_struct *p); int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); void security_task_to_inode(struct task_struct *p, struct inode *inode); @@ -980,11 +979,6 @@ static inline int security_task_kill(struct task_struct *p, return 0; } -static inline int security_task_wait(struct task_struct *p) -{ - return 0; -} - static inline int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, diff --git a/kernel/exit.c b/kernel/exit.c index 8f14b866f9f6..60f245190571 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -1360,7 +1359,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) * Returns nonzero for a final return, when we have unlocked tasklist_lock. * Returns zero if the search for a child should continue; * then ->notask_error is 0 if @p is an eligible child, - * or another error from security_task_wait(), or still -ECHILD. + * or still -ECHILD. */ static int wait_consider_task(struct wait_opts *wo, int ptrace, struct task_struct *p) @@ -1380,20 +1379,6 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, if (!ret) return ret; - ret = security_task_wait(p); - if (unlikely(ret < 0)) { - /* - * If we have not yet seen any eligible child, - * then let this error code replace -ECHILD. - * A permission error will give the user a clue - * to look for security policy problems, rather - * than for mysterious wait bugs. - */ - if (wo->notask_error) - wo->notask_error = ret; - return 0; - } - if (unlikely(exit_state == EXIT_TRACE)) { /* * ptrace == 0 means we are the natural parent. In this case @@ -1486,7 +1471,7 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, * Returns nonzero for a final return, when we have unlocked tasklist_lock. * Returns zero if the search for a child should continue; then * ->notask_error is 0 if there were any eligible children, - * or another error from security_task_wait(), or still -ECHILD. + * or still -ECHILD. */ static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk) { diff --git a/security/security.c b/security/security.c index 32052f5c76b2..8c9fee59e60a 100644 --- a/security/security.c +++ b/security/security.c @@ -1025,11 +1025,6 @@ int security_task_kill(struct task_struct *p, struct siginfo *info, return call_int_hook(task_kill, 0, p, info, sig, secid); } -int security_task_wait(struct task_struct *p) -{ - return call_int_hook(task_wait, 0, p); -} - int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { @@ -1769,7 +1764,6 @@ struct security_hook_heads security_hook_heads = { .task_movememory = LIST_HEAD_INIT(security_hook_heads.task_movememory), .task_kill = LIST_HEAD_INIT(security_hook_heads.task_kill), - .task_wait = LIST_HEAD_INIT(security_hook_heads.task_wait), .task_prctl = LIST_HEAD_INIT(security_hook_heads.task_prctl), .task_to_inode = LIST_HEAD_INIT(security_hook_heads.task_to_inode), diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 55ad878f1146..a5398fea0966 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3963,12 +3963,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, return avc_has_perm(secid, task_sid(p), SECCLASS_PROCESS, perm, NULL); } -static int selinux_task_wait(struct task_struct *p) -{ - return avc_has_perm(task_sid(p), current_sid(), SECCLASS_PROCESS, - PROCESS__SIGCHLD, NULL); -} - static void selinux_task_to_inode(struct task_struct *p, struct inode *inode) { @@ -6211,7 +6205,6 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler), LSM_HOOK_INIT(task_movememory, selinux_task_movememory), LSM_HOOK_INIT(task_kill, selinux_task_kill), - LSM_HOOK_INIT(task_wait, selinux_task_wait), LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode), LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission), diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 8da4a6b9ca4d..2166373ea5a4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2271,25 +2271,6 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, return rc; } -/** - * smack_task_wait - Smack access check for waiting - * @p: task to wait for - * - * Returns 0 - */ -static int smack_task_wait(struct task_struct *p) -{ - /* - * Allow the operation to succeed. - * Zombies are bad. - * In userless environments (e.g. phones) programs - * get marked with SMACK64EXEC and even if the parent - * and child shouldn't be talking the parent still - * may expect to know when the child exits. - */ - return 0; -} - /** * smack_task_to_inode - copy task smack into the inode blob * @p: task to copy from @@ -4658,7 +4639,6 @@ static struct security_hook_list smack_hooks[] = { LSM_HOOK_INIT(task_getscheduler, smack_task_getscheduler), LSM_HOOK_INIT(task_movememory, smack_task_movememory), LSM_HOOK_INIT(task_kill, smack_task_kill), - LSM_HOOK_INIT(task_wait, smack_task_wait), LSM_HOOK_INIT(task_to_inode, smack_task_to_inode), LSM_HOOK_INIT(ipc_permission, smack_ipc_permission), From 2cf8e2dfdf88363476f23bc600745250b94dbbed Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 12 Jan 2017 11:17:39 +0000 Subject: [PATCH 0367/1587] regmap: Fixup the kernel-doc comments on functions/structures Most of the kernel-doc comments in regmap don't actually generate correctly. This patch fixes up a few common issues, corrects some typos and adds some missing argument descriptions. The most common issues being using a : after the function name which causes the short description to not render correctly and not separating the long and short descriptions of the function. There are quite a few instances of arguments not being described or given the wrong name as well. This patch doesn't fixup functions/structures that are currently missing descriptions. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/base/regmap/regcache.c | 20 ++--- drivers/base/regmap/regmap-irq.c | 62 ++++++++------- drivers/base/regmap/regmap.c | 125 +++++++++++++++++-------------- include/linux/regmap.h | 115 ++++++++++++++++------------ 4 files changed, 179 insertions(+), 143 deletions(-) diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 4e582561e1e7..b0a0dcf32fb7 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -224,7 +224,7 @@ void regcache_exit(struct regmap *map) } /** - * regcache_read: Fetch the value of a given register from the cache. + * regcache_read - Fetch the value of a given register from the cache. * * @map: map to configure. * @reg: The register index. @@ -255,7 +255,7 @@ int regcache_read(struct regmap *map, } /** - * regcache_write: Set the value of a given register in the cache. + * regcache_write - Set the value of a given register in the cache. * * @map: map to configure. * @reg: The register index. @@ -328,7 +328,7 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, } /** - * regcache_sync: Sync the register cache with the hardware. + * regcache_sync - Sync the register cache with the hardware. * * @map: map to configure. * @@ -396,7 +396,7 @@ out: EXPORT_SYMBOL_GPL(regcache_sync); /** - * regcache_sync_region: Sync part of the register cache with the hardware. + * regcache_sync_region - Sync part of the register cache with the hardware. * * @map: map to sync. * @min: first register to sync @@ -452,7 +452,7 @@ out: EXPORT_SYMBOL_GPL(regcache_sync_region); /** - * regcache_drop_region: Discard part of the register cache + * regcache_drop_region - Discard part of the register cache * * @map: map to operate on * @min: first register to discard @@ -483,10 +483,10 @@ int regcache_drop_region(struct regmap *map, unsigned int min, EXPORT_SYMBOL_GPL(regcache_drop_region); /** - * regcache_cache_only: Put a register map into cache only mode + * regcache_cache_only - Put a register map into cache only mode * * @map: map to configure - * @cache_only: flag if changes should be written to the hardware + * @enable: flag if changes should be written to the hardware * * When a register map is marked as cache only writes to the register * map API will only update the register cache, they will not cause @@ -505,7 +505,7 @@ void regcache_cache_only(struct regmap *map, bool enable) EXPORT_SYMBOL_GPL(regcache_cache_only); /** - * regcache_mark_dirty: Indicate that HW registers were reset to default values + * regcache_mark_dirty - Indicate that HW registers were reset to default values * * @map: map to mark * @@ -527,10 +527,10 @@ void regcache_mark_dirty(struct regmap *map) EXPORT_SYMBOL_GPL(regcache_mark_dirty); /** - * regcache_cache_bypass: Put a register map into cache bypass mode + * regcache_cache_bypass - Put a register map into cache bypass mode * * @map: map to configure - * @cache_bypass: flag if changes should not be written to the cache + * @enable: flag if changes should not be written to the cache * * When a register map is marked with the cache bypass option, writes * to the register map API will only update the hardware and not the diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index ec262476d043..cd54189f2b1d 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -398,13 +398,14 @@ static const struct irq_domain_ops regmap_domain_ops = { }; /** - * regmap_add_irq_chip(): Use standard regmap IRQ controller handling + * regmap_add_irq_chip() - Use standard regmap IRQ controller handling * - * map: The regmap for the device. - * irq: The IRQ the device uses to signal interrupts - * irq_flags: The IRQF_ flags to use for the primary interrupt. - * chip: Configuration for the interrupt controller. - * data: Runtime data structure for the controller, allocated on success + * @map: The regmap for the device. + * @irq: The IRQ the device uses to signal interrupts. + * @irq_flags: The IRQF_ flags to use for the primary interrupt. + * @irq_base: Allocate at specific IRQ number if irq_base > 0. + * @chip: Configuration for the interrupt controller. + * @data: Runtime data structure for the controller, allocated on success. * * Returns 0 on success or an errno on failure. * @@ -659,12 +660,12 @@ err_alloc: EXPORT_SYMBOL_GPL(regmap_add_irq_chip); /** - * regmap_del_irq_chip(): Stop interrupt handling for a regmap IRQ chip + * regmap_del_irq_chip() - Stop interrupt handling for a regmap IRQ chip * * @irq: Primary IRQ for the device - * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() + * @d: ®map_irq_chip_data allocated by regmap_add_irq_chip() * - * This function also dispose all mapped irq on chip. + * This function also disposes of all mapped IRQs on the chip. */ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) { @@ -723,18 +724,19 @@ static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data) } /** - * devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip() + * devm_regmap_add_irq_chip() - Resource manager regmap_add_irq_chip() * - * @dev: The device pointer on which irq_chip belongs to. - * @map: The regmap for the device. - * @irq: The IRQ the device uses to signal interrupts + * @dev: The device pointer on which irq_chip belongs to. + * @map: The regmap for the device. + * @irq: The IRQ the device uses to signal interrupts * @irq_flags: The IRQF_ flags to use for the primary interrupt. - * @chip: Configuration for the interrupt controller. - * @data: Runtime data structure for the controller, allocated on success + * @irq_base: Allocate at specific IRQ number if irq_base > 0. + * @chip: Configuration for the interrupt controller. + * @data: Runtime data structure for the controller, allocated on success * * Returns 0 on success or an errno on failure. * - * The regmap_irq_chip data automatically be released when the device is + * The ®map_irq_chip_data will be automatically released when the device is * unbound. */ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq, @@ -765,11 +767,13 @@ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq, EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip); /** - * devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip() + * devm_regmap_del_irq_chip() - Resource managed regmap_del_irq_chip() * * @dev: Device for which which resource was allocated. - * @irq: Primary IRQ for the device - * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() + * @irq: Primary IRQ for the device. + * @data: ®map_irq_chip_data allocated by regmap_add_irq_chip(). + * + * A resource managed version of regmap_del_irq_chip(). */ void devm_regmap_del_irq_chip(struct device *dev, int irq, struct regmap_irq_chip_data *data) @@ -786,11 +790,11 @@ void devm_regmap_del_irq_chip(struct device *dev, int irq, EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip); /** - * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip + * regmap_irq_chip_get_base() - Retrieve interrupt base for a regmap IRQ chip + * + * @data: regmap irq controller to operate on. * * Useful for drivers to request their own IRQs. - * - * @data: regmap_irq controller to operate on. */ int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data) { @@ -800,12 +804,12 @@ int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data) EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); /** - * regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * regmap_irq_get_virq() - Map an interrupt on a chip to a virtual IRQ + * + * @data: regmap irq controller to operate on. + * @irq: index of the interrupt requested in the chip IRQs. * * Useful for drivers to request their own IRQs. - * - * @data: regmap_irq controller to operate on. - * @irq: index of the interrupt requested in the chip IRQs */ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) { @@ -818,14 +822,14 @@ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) EXPORT_SYMBOL_GPL(regmap_irq_get_virq); /** - * regmap_irq_get_domain(): Retrieve the irq_domain for the chip + * regmap_irq_get_domain() - Retrieve the irq_domain for the chip + * + * @data: regmap_irq controller to operate on. * * Useful for drivers to request their own IRQs and for integration * with subsystems. For ease of integration NULL is accepted as a * domain, allowing devices to just call this even if no domain is * allocated. - * - * @data: regmap_irq controller to operate on. */ struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data) { diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ae63bb0875ea..0e770ba8d361 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1091,8 +1091,7 @@ static void regmap_field_init(struct regmap_field *rm_field, } /** - * devm_regmap_field_alloc(): Allocate and initialise a register field - * in a register map. + * devm_regmap_field_alloc() - Allocate and initialise a register field. * * @dev: Device that will be interacted with * @regmap: regmap bank in which this register field is located. @@ -1118,13 +1117,15 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev, EXPORT_SYMBOL_GPL(devm_regmap_field_alloc); /** - * devm_regmap_field_free(): Free register field allocated using - * devm_regmap_field_alloc. Usally drivers need not call this function, - * as the memory allocated via devm will be freed as per device-driver - * life-cyle. + * devm_regmap_field_free() - Free a register field allocated using + * devm_regmap_field_alloc. * * @dev: Device that will be interacted with * @field: regmap field which should be freed. + * + * Free register field allocated using devm_regmap_field_alloc(). Usually + * drivers need not call this function, as the memory allocated via devm + * will be freed as per device-driver life-cyle. */ void devm_regmap_field_free(struct device *dev, struct regmap_field *field) @@ -1134,8 +1135,7 @@ void devm_regmap_field_free(struct device *dev, EXPORT_SYMBOL_GPL(devm_regmap_field_free); /** - * regmap_field_alloc(): Allocate and initialise a register field - * in a register map. + * regmap_field_alloc() - Allocate and initialise a register field. * * @regmap: regmap bank in which this register field is located. * @reg_field: Register field with in the bank. @@ -1159,7 +1159,8 @@ struct regmap_field *regmap_field_alloc(struct regmap *regmap, EXPORT_SYMBOL_GPL(regmap_field_alloc); /** - * regmap_field_free(): Free register field allocated using regmap_field_alloc + * regmap_field_free() - Free register field allocated using + * regmap_field_alloc. * * @field: regmap field which should be freed. */ @@ -1170,7 +1171,7 @@ void regmap_field_free(struct regmap_field *field) EXPORT_SYMBOL_GPL(regmap_field_free); /** - * regmap_reinit_cache(): Reinitialise the current register cache + * regmap_reinit_cache() - Reinitialise the current register cache * * @map: Register map to operate on. * @config: New configuration. Only the cache data will be used. @@ -1205,7 +1206,9 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) EXPORT_SYMBOL_GPL(regmap_reinit_cache); /** - * regmap_exit(): Free a previously allocated register map + * regmap_exit() - Free a previously allocated register map + * + * @map: Register map to operate on. */ void regmap_exit(struct regmap *map) { @@ -1245,7 +1248,7 @@ static int dev_get_regmap_match(struct device *dev, void *res, void *data) } /** - * dev_get_regmap(): Obtain the regmap (if any) for a device + * dev_get_regmap() - Obtain the regmap (if any) for a device * * @dev: Device to retrieve the map for * @name: Optional name for the register map, usually NULL. @@ -1268,7 +1271,7 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name) EXPORT_SYMBOL_GPL(dev_get_regmap); /** - * regmap_get_device(): Obtain the device from a regmap + * regmap_get_device() - Obtain the device from a regmap * * @map: Register map to operate on. * @@ -1654,7 +1657,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, } /** - * regmap_write(): Write a value to a single register + * regmap_write() - Write a value to a single register * * @map: Register map to write to * @reg: Register to write to @@ -1681,7 +1684,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) EXPORT_SYMBOL_GPL(regmap_write); /** - * regmap_write_async(): Write a value to a single register asynchronously + * regmap_write_async() - Write a value to a single register asynchronously * * @map: Register map to write to * @reg: Register to write to @@ -1712,7 +1715,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val) EXPORT_SYMBOL_GPL(regmap_write_async); /** - * regmap_raw_write(): Write raw values to one or more registers + * regmap_raw_write() - Write raw values to one or more registers * * @map: Register map to write to * @reg: Initial register to write to @@ -1750,9 +1753,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, EXPORT_SYMBOL_GPL(regmap_raw_write); /** - * regmap_field_update_bits_base(): - * Perform a read/modify/write cycle on the register field - * with change, async, force option + * regmap_field_update_bits_base() - Perform a read/modify/write cycle a + * register field. * * @field: Register field to write to * @mask: Bitmask to change @@ -1761,6 +1763,9 @@ EXPORT_SYMBOL_GPL(regmap_raw_write); * @async: Boolean indicating asynchronously * @force: Boolean indicating use force update * + * Perform a read/modify/write cycle on the register field with change, + * async, force option. + * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */ @@ -1777,9 +1782,8 @@ int regmap_field_update_bits_base(struct regmap_field *field, EXPORT_SYMBOL_GPL(regmap_field_update_bits_base); /** - * regmap_fields_update_bits_base(): - * Perform a read/modify/write cycle on the register field - * with change, async, force option + * regmap_fields_update_bits_base() - Perform a read/modify/write cycle a + * register field with port ID * * @field: Register field to write to * @id: port ID @@ -1808,8 +1812,8 @@ int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id, } EXPORT_SYMBOL_GPL(regmap_fields_update_bits_base); -/* - * regmap_bulk_write(): Write multiple registers to the device +/** + * regmap_bulk_write() - Write multiple registers to the device * * @map: Register map to write to * @reg: First register to be write from @@ -2174,18 +2178,18 @@ static int _regmap_multi_reg_write(struct regmap *map, return _regmap_raw_multi_reg_write(map, regs, num_regs); } -/* - * regmap_multi_reg_write(): Write multiple registers to the device - * - * where the set of register,value pairs are supplied in any order, - * possibly not all in a single range. +/** + * regmap_multi_reg_write() - Write multiple registers to the device * * @map: Register map to write to * @regs: Array of structures containing register,value to be written * @num_regs: Number of registers to write * + * Write multiple registers to the device where the set of register, value + * pairs are supplied in any order, possibly not all in a single range. + * * The 'normal' block write mode will send ultimately send data on the - * target bus as R,V1,V2,V3,..,Vn where successively higer registers are + * target bus as R,V1,V2,V3,..,Vn where successively higher registers are * addressed. However, this alternative block multi write mode will send * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device * must of course support the mode. @@ -2208,16 +2212,17 @@ int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, } EXPORT_SYMBOL_GPL(regmap_multi_reg_write); -/* - * regmap_multi_reg_write_bypassed(): Write multiple registers to the - * device but not the cache - * - * where the set of register are supplied in any order +/** + * regmap_multi_reg_write_bypassed() - Write multiple registers to the + * device but not the cache * * @map: Register map to write to * @regs: Array of structures containing register,value to be written * @num_regs: Number of registers to write * + * Write multiple registers to the device but not the cache where the set + * of register are supplied in any order. + * * This function is intended to be used for writing a large block of data * atomically to the device in single transfer for those I2C client devices * that implement this alternative block write mode. @@ -2248,8 +2253,8 @@ int regmap_multi_reg_write_bypassed(struct regmap *map, EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed); /** - * regmap_raw_write_async(): Write raw values to one or more registers - * asynchronously + * regmap_raw_write_async() - Write raw values to one or more registers + * asynchronously * * @map: Register map to write to * @reg: Initial register to write to @@ -2385,7 +2390,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg, } /** - * regmap_read(): Read a value from a single register + * regmap_read() - Read a value from a single register * * @map: Register map to read from * @reg: Register to be read from @@ -2412,7 +2417,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) EXPORT_SYMBOL_GPL(regmap_read); /** - * regmap_raw_read(): Read raw data from the device + * regmap_raw_read() - Read raw data from the device * * @map: Register map to read from * @reg: First register to be read from @@ -2477,7 +2482,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, EXPORT_SYMBOL_GPL(regmap_raw_read); /** - * regmap_field_read(): Read a value to a single register field + * regmap_field_read() - Read a value to a single register field * * @field: Register field to read from * @val: Pointer to store read value @@ -2502,7 +2507,7 @@ int regmap_field_read(struct regmap_field *field, unsigned int *val) EXPORT_SYMBOL_GPL(regmap_field_read); /** - * regmap_fields_read(): Read a value to a single register field with port ID + * regmap_fields_read() - Read a value to a single register field with port ID * * @field: Register field to read from * @id: port ID @@ -2535,7 +2540,7 @@ int regmap_fields_read(struct regmap_field *field, unsigned int id, EXPORT_SYMBOL_GPL(regmap_fields_read); /** - * regmap_bulk_read(): Read multiple registers from the device + * regmap_bulk_read() - Read multiple registers from the device * * @map: Register map to read from * @reg: First register to be read from @@ -2692,9 +2697,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, } /** - * regmap_update_bits_base: - * Perform a read/modify/write cycle on the - * register map with change, async, force option + * regmap_update_bits_base() - Perform a read/modify/write cycle on a register * * @map: Register map to update * @reg: Register to update @@ -2704,10 +2707,14 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, * @async: Boolean indicating asynchronously * @force: Boolean indicating use force update * - * if async was true, - * With most buses the read must be done synchronously so this is most - * useful for devices with a cache which do not need to interact with - * the hardware to determine the current register value. + * Perform a read/modify/write cycle on a register map with change, async, force + * options. + * + * If async is true: + * + * With most buses the read must be done synchronously so this is most useful + * for devices with a cache which do not need to interact with the hardware to + * determine the current register value. * * Returns zero for success, a negative number on error. */ @@ -2765,7 +2772,7 @@ static int regmap_async_is_done(struct regmap *map) } /** - * regmap_async_complete: Ensure all asynchronous I/O has completed. + * regmap_async_complete - Ensure all asynchronous I/O has completed. * * @map: Map to operate on. * @@ -2797,8 +2804,8 @@ int regmap_async_complete(struct regmap *map) EXPORT_SYMBOL_GPL(regmap_async_complete); /** - * regmap_register_patch: Register and apply register updates to be applied - * on device initialistion + * regmap_register_patch - Register and apply register updates to be applied + * on device initialistion * * @map: Register map to apply updates to. * @regs: Values to update. @@ -2855,8 +2862,10 @@ int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, } EXPORT_SYMBOL_GPL(regmap_register_patch); -/* - * regmap_get_val_bytes(): Report the size of a register value +/** + * regmap_get_val_bytes() - Report the size of a register value + * + * @map: Register map to operate on. * * Report the size of a register value, mainly intended to for use by * generic infrastructure built on top of regmap. @@ -2871,7 +2880,9 @@ int regmap_get_val_bytes(struct regmap *map) EXPORT_SYMBOL_GPL(regmap_get_val_bytes); /** - * regmap_get_max_register(): Report the max register value + * regmap_get_max_register() - Report the max register value + * + * @map: Register map to operate on. * * Report the max register value, mainly intended to for use by * generic infrastructure built on top of regmap. @@ -2883,7 +2894,9 @@ int regmap_get_max_register(struct regmap *map) EXPORT_SYMBOL_GPL(regmap_get_max_register); /** - * regmap_get_reg_stride(): Report the register address stride + * regmap_get_reg_stride() - Report the register address stride + * + * @map: Register map to operate on. * * Report the register address stride, mainly intended to for use by * generic infrastructure built on top of regmap. diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 9adc7b21903d..38a85d50fefd 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -39,12 +39,13 @@ enum regcache_type { }; /** - * Default value for a register. We use an array of structs rather - * than a simple array as many modern devices have very sparse - * register maps. + * struct reg_default - Default value for a register. * * @reg: Register address. * @def: Register default value. + * + * We use an array of structs rather than a simple array as many modern devices + * have very sparse register maps. */ struct reg_default { unsigned int reg; @@ -52,12 +53,14 @@ struct reg_default { }; /** - * Register/value pairs for sequences of writes with an optional delay in - * microseconds to be applied after each write. + * struct reg_sequence - An individual write from a sequence of writes. * * @reg: Register address. * @def: Register value. * @delay_us: Delay to be applied after the register write in microseconds + * + * Register/value pairs for sequences of writes with an optional delay in + * microseconds to be applied after each write. */ struct reg_sequence { unsigned int reg; @@ -97,6 +100,7 @@ struct reg_sequence { /** * regmap_read_poll_timeout - Poll until a condition is met or a timeout occurs + * * @map: Regmap to read from * @addr: Address to poll * @val: Unsigned integer variable to read the value into @@ -145,8 +149,8 @@ enum regmap_endian { }; /** - * A register range, used for access related checks - * (readable/writeable/volatile/precious checks) + * struct regmap_range - A register range, used for access related checks + * (readable/writeable/volatile/precious checks) * * @range_min: address of first register * @range_max: address of last register @@ -158,16 +162,18 @@ struct regmap_range { #define regmap_reg_range(low, high) { .range_min = low, .range_max = high, } -/* - * A table of ranges including some yes ranges and some no ranges. - * If a register belongs to a no_range, the corresponding check function - * will return false. If a register belongs to a yes range, the corresponding - * check function will return true. "no_ranges" are searched first. +/** + * struct regmap_access_table - A table of register ranges for access checks * * @yes_ranges : pointer to an array of regmap ranges used as "yes ranges" * @n_yes_ranges: size of the above array * @no_ranges: pointer to an array of regmap ranges used as "no ranges" * @n_no_ranges: size of the above array + * + * A table of ranges including some yes ranges and some no ranges. + * If a register belongs to a no_range, the corresponding check function + * will return false. If a register belongs to a yes range, the corresponding + * check function will return true. "no_ranges" are searched first. */ struct regmap_access_table { const struct regmap_range *yes_ranges; @@ -180,7 +186,7 @@ typedef void (*regmap_lock)(void *); typedef void (*regmap_unlock)(void *); /** - * Configuration for the register map of a device. + * struct regmap_config - Configuration for the register map of a device. * * @name: Optional name of the regmap. Useful when a device has multiple * register regions. @@ -313,22 +319,24 @@ struct regmap_config { }; /** - * Configuration for indirectly accessed or paged registers. - * Registers, mapped to this virtual range, are accessed in two steps: - * 1. page selector register update; - * 2. access through data window registers. + * struct regmap_range_cfg - Configuration for indirectly accessed or paged + * registers. * * @name: Descriptive name for diagnostics * * @range_min: Address of the lowest register address in virtual range. * @range_max: Address of the highest register in virtual range. * - * @page_sel_reg: Register with selector field. - * @page_sel_mask: Bit shift for selector value. - * @page_sel_shift: Bit mask for selector value. + * @selector_reg: Register with selector field. + * @selector_mask: Bit shift for selector value. + * @selector_shift: Bit mask for selector value. * * @window_start: Address of first (lowest) register in data window. * @window_len: Number of registers in data window. + * + * Registers, mapped to this virtual range, are accessed in two steps: + * 1. page selector register update; + * 2. access through data window registers. */ struct regmap_range_cfg { const char *name; @@ -371,7 +379,8 @@ typedef struct regmap_async *(*regmap_hw_async_alloc)(void); typedef void (*regmap_hw_free_context)(void *context); /** - * Description of a hardware bus for the register map infrastructure. + * struct regmap_bus - Description of a hardware bus for the register map + * infrastructure. * * @fast_io: Register IO is fast. Use a spinlock instead of a mutex * to perform locking. This field is ignored if custom lock/unlock @@ -384,6 +393,10 @@ typedef void (*regmap_hw_free_context)(void *context); * must serialise with respect to non-async I/O. * @reg_write: Write a single register value to the given register address. This * write operation has to complete when returning from the function. + * @reg_update_bits: Update bits operation to be used against volatile + * registers, intended for devices supporting some mechanism + * for setting clearing bits without having to + * read/modify/write. * @read: Read operation. Data is returned in the buffer used to transmit * data. * @reg_read: Read a single register value from a given register address. @@ -513,7 +526,7 @@ struct regmap *__devm_regmap_init_ac97(struct snd_ac97 *ac97, #endif /** - * regmap_init(): Initialise register map + * regmap_init() - Initialise register map * * @dev: Device that will be interacted with * @bus: Bus-specific callbacks to use with device @@ -531,7 +544,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, const struct regmap_config *config); /** - * regmap_init_i2c(): Initialise register map + * regmap_init_i2c() - Initialise register map * * @i2c: Device that will be interacted with * @config: Configuration for register map @@ -544,9 +557,9 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, i2c, config) /** - * regmap_init_spi(): Initialise register map + * regmap_init_spi() - Initialise register map * - * @spi: Device that will be interacted with + * @dev: Device that will be interacted with * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer to @@ -557,8 +570,9 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, dev, config) /** - * regmap_init_spmi_base(): Create regmap for the Base register space - * @sdev: SPMI device that will be interacted with + * regmap_init_spmi_base() - Create regmap for the Base register space + * + * @dev: SPMI device that will be interacted with * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer to @@ -569,8 +583,9 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, dev, config) /** - * regmap_init_spmi_ext(): Create regmap for Ext register space - * @sdev: Device that will be interacted with + * regmap_init_spmi_ext() - Create regmap for Ext register space + * + * @dev: Device that will be interacted with * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer to @@ -581,7 +596,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, dev, config) /** - * regmap_init_mmio_clk(): Initialise register map with register clock + * regmap_init_mmio_clk() - Initialise register map with register clock * * @dev: Device that will be interacted with * @clk_id: register clock consumer ID @@ -596,7 +611,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, dev, clk_id, regs, config) /** - * regmap_init_mmio(): Initialise register map + * regmap_init_mmio() - Initialise register map * * @dev: Device that will be interacted with * @regs: Pointer to memory-mapped IO region @@ -609,7 +624,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, regmap_init_mmio_clk(dev, NULL, regs, config) /** - * regmap_init_ac97(): Initialise AC'97 register map + * regmap_init_ac97() - Initialise AC'97 register map * * @ac97: Device that will be interacted with * @config: Configuration for register map @@ -623,7 +638,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); /** - * devm_regmap_init(): Initialise managed register map + * devm_regmap_init() - Initialise managed register map * * @dev: Device that will be interacted with * @bus: Bus-specific callbacks to use with device @@ -640,7 +655,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); dev, bus, bus_context, config) /** - * devm_regmap_init_i2c(): Initialise managed register map + * devm_regmap_init_i2c() - Initialise managed register map * * @i2c: Device that will be interacted with * @config: Configuration for register map @@ -654,9 +669,9 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); i2c, config) /** - * devm_regmap_init_spi(): Initialise register map + * devm_regmap_init_spi() - Initialise register map * - * @spi: Device that will be interacted with + * @dev: Device that will be interacted with * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer @@ -668,8 +683,9 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); dev, config) /** - * devm_regmap_init_spmi_base(): Create managed regmap for Base register space - * @sdev: SPMI device that will be interacted with + * devm_regmap_init_spmi_base() - Create managed regmap for Base register space + * + * @dev: SPMI device that will be interacted with * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer @@ -681,8 +697,9 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); dev, config) /** - * devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space - * @sdev: SPMI device that will be interacted with + * devm_regmap_init_spmi_ext() - Create managed regmap for Ext register space + * + * @dev: SPMI device that will be interacted with * @config: Configuration for register map * * The return value will be an ERR_PTR() on error or a valid pointer @@ -694,7 +711,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); dev, config) /** - * devm_regmap_init_mmio_clk(): Initialise managed register map with clock + * devm_regmap_init_mmio_clk() - Initialise managed register map with clock * * @dev: Device that will be interacted with * @clk_id: register clock consumer ID @@ -710,7 +727,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); dev, clk_id, regs, config) /** - * devm_regmap_init_mmio(): Initialise managed register map + * devm_regmap_init_mmio() - Initialise managed register map * * @dev: Device that will be interacted with * @regs: Pointer to memory-mapped IO region @@ -724,7 +741,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); devm_regmap_init_mmio_clk(dev, NULL, regs, config) /** - * devm_regmap_init_ac97(): Initialise AC'97 register map + * devm_regmap_init_ac97() - Initialise AC'97 register map * * @ac97: Device that will be interacted with * @config: Configuration for register map @@ -799,7 +816,7 @@ bool regmap_reg_in_ranges(unsigned int reg, unsigned int nranges); /** - * Description of an register field + * struct reg_field - Description of an register field * * @reg: Offset of the register within the regmap bank * @lsb: lsb of the register field. @@ -840,7 +857,7 @@ int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id, bool *change, bool async, bool force); /** - * Description of an IRQ for the generic regmap irq_chip. + * struct regmap_irq - Description of an IRQ for the generic regmap irq_chip. * * @reg_offset: Offset of the status/mask register within the bank * @mask: Mask used to flag/control the register. @@ -860,9 +877,7 @@ struct regmap_irq { [_irq] = { .reg_offset = (_off), .mask = (_mask) } /** - * Description of a generic regmap irq_chip. This is not intended to - * handle every possible interrupt controller, but it should handle a - * substantial proportion of those that are found in the wild. + * struct regmap_irq_chip - Description of a generic regmap irq_chip. * * @name: Descriptive name for IRQ controller. * @@ -896,6 +911,10 @@ struct regmap_irq { * after handling the interrupts in regmap_irq_handler(). * @irq_drv_data: Driver specific IRQ data which is passed as parameter when * driver specific pre/post interrupt handler is called. + * + * This is not intended to handle every possible interrupt controller, but + * it should handle a substantial proportion of those that are found in the + * wild. */ struct regmap_irq_chip { const char *name; From 66d228a2bf03b163ddaeca5f24f1ff89a84ad668 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 11 Jan 2017 17:44:25 +0000 Subject: [PATCH 0368/1587] regulator: core: Don't use regulators as supplies until the parent is bound When regulators are successfully registered, we check to see if the regulator is a supply for any other registered regulator and if so add the new regulator as the supply for the existing regulator(s). Some devices, such as Power Management ICs, may register a series of regulators when probed and there are cases where one of the regulators may fail to register and defer the probing of the parent device. In this case any successfully registered regulators would be unregistered so that they can be re-registered at some time later when the probe is attempted again. However, if one of the regulators that was registered was added as a supply to another registered regulator (that did not belong to the same parent device), then this supply regulator was unregister again because the parent device is probe deferred, then a regulator could be holding an invalid reference to a supply regulator that has been unregistered. This will lead to a system crash if that regulator is then used. Although it would be possible to check when unregistering a regulator if any other regulator in the system is using it as a supply, it still may not be possible to remove it as a supply if this other regulator is in use. Therefore, fix this by preventing any regulator from adding another regulator as a supply if the parent device for the supply regulator has not been bound and if the parent device for the supply and the regulator are different. This will allow a parent device that is registering regulators to be probe deferred and ensure that none of the regulators it has registered are used as supplies for any other regulator from another device. Signed-off-by: Jon Hunter Signed-off-by: Mark Brown --- drivers/regulator/core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 04baac9a165b..bcf67abd1cd2 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1553,6 +1553,19 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) } } + /* + * If the supply's parent device is not the same as the + * regulator's parent device, then ensure the parent device + * is bound before we resolve the supply, in case the parent + * device get probe deferred and unregisters the supply. + */ + if (r->dev.parent && r->dev.parent != rdev->dev.parent) { + if (!device_is_bound(r->dev.parent)) { + put_device(&r->dev); + return -EPROBE_DEFER; + } + } + /* Recursively resolve the supply of the supply */ ret = regulator_resolve_supply(r); if (ret < 0) { From 950b0d91dc108f54bccca5a2f75bb46f2df63d29 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 11 Jan 2017 14:13:34 -0800 Subject: [PATCH 0369/1587] pinctrl: core: Fix regression caused by delayed work for hogs Commit df61b366af26 ("pinctrl: core: Use delayed work for hogs") caused a regression at least with sh-pfc that is also a GPIO controller as noted by Geert Uytterhoeven . As the original pinctrl_register() has issues calling pin controller driver functions early before the controller has finished registering, we can't just revert commit df61b366af26. That would break the drivers using GENERIC_PINCTRL_GROUPS or GENERIC_PINMUX_FUNCTIONS. So let's fix the issue with the following steps as a single patch: 1. Revert the late_init parts of commit df61b366af26. The late_init clearly won't work and we have to just give up on fixing pinctrl_register() for GENERIC_PINCTRL_GROUPS and GENERIC_PINMUX_FUNCTIONS. 2. Split pinctrl_register() into two parts By splitting pinctrl_register() into pinctrl_init_controller() and pinctrl_create_and_start() we have better control over when it's safe to call pinctrl_create(). 3. Introduce a new pinctrl_register_and_init() function As suggested by Linus Walleij , we can just introduce a new function for the controllers that need pinctrl_create() called later. 4. Convert the four known problem cases to use new function Let's convert pinctrl-imx, pinctrl-single, sh-pfc and ti-iodelay to use the new function to fix the issues. The rest of the drivers can be converted later. Let's also update Documentation/pinctrl.txt accordingly because of the known issues with pinctrl_register(). Fixes: df61b366af26 ("pinctrl: core: Use delayed work for hogs") Reported-by: Geert Uytterhoeven Cc: Gary Bisson Signed-off-by: Tony Lindgren Tested-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 4 +- drivers/pinctrl/core.c | 201 ++++++++++++++++-------- drivers/pinctrl/core.h | 2 - drivers/pinctrl/freescale/pinctrl-imx.c | 8 +- drivers/pinctrl/pinctrl-single.c | 5 +- drivers/pinctrl/sh-pfc/pinctrl.c | 4 +- drivers/pinctrl/ti/pinctrl-ti-iodelay.c | 5 +- include/linux/pinctrl/pinctrl.h | 15 ++ 8 files changed, 165 insertions(+), 79 deletions(-) diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 0d3b9ce0a0b9..54bd5faa8782 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -79,9 +79,7 @@ int __init foo_probe(void) { struct pinctrl_dev *pctl; - pctl = pinctrl_register(&foo_desc, , NULL); - if (!pctl) - pr_err("could not register foo pin driver\n"); + return pinctrl_register_and_init(&foo_desc, , NULL, &pctl); } To enable the pinctrl subsystem and the subgroups for PINMUX and PINCONF and diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 65c0ae0969dc..bc73a63163ee 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1905,59 +1905,14 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev) } /** - * pinctrl_late_init() - finish pin controller device registration - * @work: work struct - */ -static void pinctrl_late_init(struct work_struct *work) -{ - struct pinctrl_dev *pctldev; - - pctldev = container_of(work, struct pinctrl_dev, late_init.work); - - /* - * If the pin controller does NOT have hogs, this will report an - * error and we skip over this entire branch. This is why we can - * call this function directly when we do not have hogs on the - * device. - */ - pctldev->p = create_pinctrl(pctldev->dev, pctldev); - if (!IS_ERR(pctldev->p)) { - kref_get(&pctldev->p->users); - pctldev->hog_default = - pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT); - if (IS_ERR(pctldev->hog_default)) { - dev_dbg(pctldev->dev, - "failed to lookup the default state\n"); - } else { - if (pinctrl_select_state(pctldev->p, - pctldev->hog_default)) - dev_err(pctldev->dev, - "failed to select default state\n"); - } - - pctldev->hog_sleep = - pinctrl_lookup_state(pctldev->p, - PINCTRL_STATE_SLEEP); - if (IS_ERR(pctldev->hog_sleep)) - dev_dbg(pctldev->dev, - "failed to lookup the sleep state\n"); - } - - mutex_lock(&pinctrldev_list_mutex); - list_add_tail(&pctldev->node, &pinctrldev_list); - mutex_unlock(&pinctrldev_list_mutex); - - pinctrl_init_device_debugfs(pctldev); -} - -/** - * pinctrl_register() - register a pin controller device + * pinctrl_init_controller() - init a pin controller device * @pctldesc: descriptor for this pin controller * @dev: parent device for this pin controller * @driver_data: private pin controller data for this pin controller */ -struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, - struct device *dev, void *driver_data) +struct pinctrl_dev *pinctrl_init_controller(struct pinctrl_desc *pctldesc, + struct device *dev, + void *driver_data) { struct pinctrl_dev *pctldev; int ret; @@ -1983,7 +1938,6 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, INIT_RADIX_TREE(&pctldev->pin_function_tree, GFP_KERNEL); #endif INIT_LIST_HEAD(&pctldev->gpio_ranges); - INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init); pctldev->dev = dev; mutex_init(&pctldev->mutex); @@ -2018,17 +1972,6 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, goto out_err; } - /* - * If the device has hogs we want the probe() function of the driver - * to complete before we go in and hog them and add the pin controller - * to the list of controllers. If it has no hogs, we can just complete - * the registration immediately. - */ - if (pinctrl_dt_has_hogs(pctldev)) - schedule_delayed_work(&pctldev->late_init, 0); - else - pinctrl_late_init(&pctldev->late_init.work); - return pctldev; out_err: @@ -2036,8 +1979,107 @@ out_err: kfree(pctldev); return ERR_PTR(ret); } + +static int pinctrl_create_and_start(struct pinctrl_dev *pctldev) +{ + pctldev->p = create_pinctrl(pctldev->dev, pctldev); + if (!IS_ERR(pctldev->p)) { + kref_get(&pctldev->p->users); + pctldev->hog_default = + pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT); + if (IS_ERR(pctldev->hog_default)) { + dev_dbg(pctldev->dev, + "failed to lookup the default state\n"); + } else { + if (pinctrl_select_state(pctldev->p, + pctldev->hog_default)) + dev_err(pctldev->dev, + "failed to select default state\n"); + } + + pctldev->hog_sleep = + pinctrl_lookup_state(pctldev->p, + PINCTRL_STATE_SLEEP); + if (IS_ERR(pctldev->hog_sleep)) + dev_dbg(pctldev->dev, + "failed to lookup the sleep state\n"); + } + + mutex_lock(&pinctrldev_list_mutex); + list_add_tail(&pctldev->node, &pinctrldev_list); + mutex_unlock(&pinctrldev_list_mutex); + + pinctrl_init_device_debugfs(pctldev); + + return 0; +} + +/** + * pinctrl_register() - register a pin controller device + * @pctldesc: descriptor for this pin controller + * @dev: parent device for this pin controller + * @driver_data: private pin controller data for this pin controller + * + * Note that pinctrl_register() is known to have problems as the pin + * controller driver functions are called before the driver has a + * struct pinctrl_dev handle. To avoid issues later on, please use the + * new pinctrl_register_and_init() below instead. + */ +struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, + struct device *dev, void *driver_data) +{ + struct pinctrl_dev *pctldev; + int error; + + pctldev = pinctrl_init_controller(pctldesc, dev, driver_data); + if (IS_ERR(pctldev)) + return pctldev; + + error = pinctrl_create_and_start(pctldev); + if (error) { + mutex_destroy(&pctldev->mutex); + kfree(pctldev); + + return ERR_PTR(error); + } + + return pctldev; + +} EXPORT_SYMBOL_GPL(pinctrl_register); +int pinctrl_register_and_init(struct pinctrl_desc *pctldesc, + struct device *dev, void *driver_data, + struct pinctrl_dev **pctldev) +{ + struct pinctrl_dev *p; + int error; + + p = pinctrl_init_controller(pctldesc, dev, driver_data); + if (IS_ERR(p)) + return PTR_ERR(p); + + /* + * We have pinctrl_start() call functions in the pin controller + * driver with create_pinctrl() for at least dt_node_to_map(). So + * let's make sure pctldev is properly initialized for the + * pin controller driver before we do anything. + */ + *pctldev = p; + + error = pinctrl_create_and_start(p); + if (error) { + mutex_destroy(&p->mutex); + kfree(p); + *pctldev = NULL; + + return error; + } + + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_register_and_init); + /** * pinctrl_unregister() - unregister pinmux * @pctldev: pin controller to unregister @@ -2052,7 +2094,6 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) if (pctldev == NULL) return; - cancel_delayed_work_sync(&pctldev->late_init); mutex_lock(&pctldev->mutex); pinctrl_remove_device_debugfs(pctldev); mutex_unlock(&pctldev->mutex); @@ -2133,6 +2174,42 @@ struct pinctrl_dev *devm_pinctrl_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_pinctrl_register); +/** + * devm_pinctrl_register_and_init() - Resource managed pinctrl register and init + * @dev: parent device for this pin controller + * @pctldesc: descriptor for this pin controller + * @driver_data: private pin controller data for this pin controller + * + * Returns an error pointer if pincontrol register failed. Otherwise + * it returns valid pinctrl handle. + * + * The pinctrl device will be automatically released when the device is unbound. + */ +int devm_pinctrl_register_and_init(struct device *dev, + struct pinctrl_desc *pctldesc, + void *driver_data, + struct pinctrl_dev **pctldev) +{ + struct pinctrl_dev **ptr; + int error; + + ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + error = pinctrl_register_and_init(pctldesc, dev, driver_data, pctldev); + if (error) { + devres_free(ptr); + return error; + } + + *ptr = *pctldev; + devres_add(dev, ptr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_pinctrl_register_and_init); + /** * devm_pinctrl_unregister() - Resource managed version of pinctrl_unregister(). * @dev: device for which which resource was allocated diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index ad812a2d7248..1c35de59a658 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -37,7 +37,6 @@ struct pinctrl_gpio_range; * @p: result of pinctrl_get() for this device * @hog_default: default state for pins hogged by this device * @hog_sleep: sleep state for pins hogged by this device - * @late_init: delayed work for pin controller to finish registration * @mutex: mutex taken on each pin controller specific action * @device_root: debugfs root for this device */ @@ -60,7 +59,6 @@ struct pinctrl_dev { struct pinctrl *p; struct pinctrl_state *hog_default; struct pinctrl_state *hog_sleep; - struct delayed_work late_init; struct mutex mutex; #ifdef CONFIG_DEBUG_FS struct dentry *device_root; diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index bccd9416d44f..a7ace9e1ad81 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -774,11 +774,11 @@ int imx_pinctrl_probe(struct platform_device *pdev, ipctl->info = info; ipctl->dev = info->dev; platform_set_drvdata(pdev, ipctl); - ipctl->pctl = devm_pinctrl_register(&pdev->dev, - imx_pinctrl_desc, ipctl); - if (IS_ERR(ipctl->pctl)) { + ret = devm_pinctrl_register_and_init(&pdev->dev, + imx_pinctrl_desc, ipctl, + &ipctl->pctl); + if (ret) { dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); - ret = PTR_ERR(ipctl->pctl); goto free; } diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 8408263de466..d23e0e0aeb22 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1747,10 +1747,9 @@ static int pcs_probe(struct platform_device *pdev) if (ret < 0) goto free; - pcs->pctl = pinctrl_register(&pcs->desc, pcs->dev, pcs); - if (IS_ERR(pcs->pctl)) { + ret = pinctrl_register_and_init(&pcs->desc, pcs->dev, pcs, &pcs->pctl); + if (ret) { dev_err(pcs->dev, "could not register single pinctrl driver\n"); - ret = PTR_ERR(pcs->pctl); goto free; } diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index fcacfa73ef6e..08150a321be6 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -816,6 +816,6 @@ int sh_pfc_register_pinctrl(struct sh_pfc *pfc) pmx->pctl_desc.pins = pmx->pins; pmx->pctl_desc.npins = pfc->info->nr_pins; - pmx->pctl = devm_pinctrl_register(pfc->dev, &pmx->pctl_desc, pmx); - return PTR_ERR_OR_ZERO(pmx->pctl); + return devm_pinctrl_register_and_init(pfc->dev, &pmx->pctl_desc, pmx, + &pmx->pctl); } diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c index 3b86d3db7358..7f472f123515 100644 --- a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c +++ b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c @@ -891,10 +891,9 @@ static int ti_iodelay_probe(struct platform_device *pdev) iod->desc.name = dev_name(dev); iod->desc.owner = THIS_MODULE; - iod->pctl = pinctrl_register(&iod->desc, dev, iod); - if (!iod->pctl) { + ret = pinctrl_register_and_init(&iod->desc, dev, iod, &iod->pctl); + if (ret) { dev_err(dev, "Failed to register pinctrl\n"); - ret = -ENODEV; goto exit_out; } diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index a42e57da270d..8ce2d87a238b 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -141,12 +141,27 @@ struct pinctrl_desc { }; /* External interface to pin controller */ + +extern int pinctrl_register_and_init(struct pinctrl_desc *pctldesc, + struct device *dev, void *driver_data, + struct pinctrl_dev **pctldev); + +/* Please use pinctrl_register_and_init() instead */ extern struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, struct device *dev, void *driver_data); + extern void pinctrl_unregister(struct pinctrl_dev *pctldev); + +extern int devm_pinctrl_register_and_init(struct device *dev, + struct pinctrl_desc *pctldesc, + void *driver_data, + struct pinctrl_dev **pctldev); + +/* Please use devm_pinctrl_register_and_init() instead */ extern struct pinctrl_dev *devm_pinctrl_register(struct device *dev, struct pinctrl_desc *pctldesc, void *driver_data); + extern void devm_pinctrl_unregister(struct device *dev, struct pinctrl_dev *pctldev); From 46daed6ebd4bf357f77d231075f1b001f8707b48 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 12 Jan 2017 17:03:34 +0100 Subject: [PATCH 0370/1587] pinctrl: Initialize pinctrl_dev.node The struct pinctrl_dev's node field is not properly set up, which means the .prev and .next fields will be NULL. That's not something that the linked list code can deal with, so extra care must be taken when using these fields. An example of this is introduced in commit 3429fb3cda34 ("pinctrl: Fix panic when pinctrl devices with hogs are unregistered") where list_del() is made conditional on the pinctrl device being part of the pinctrl device list. This is to ensure that list_del() won't crash upon encountering a NULL pointer in .prev and/or .next. After initializing the list head there's no need to jump through these extra hoops and list_del() will work unconditionally. This is because the initialized list head points to itself and therefore the .prev and .next fields can be properly dereferenced. Signed-off-by: Thierry Reding Acked-by: Jon Hunter Tested-by: Jon Hunter Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index bc73a63163ee..2f853e03d28d 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1938,6 +1938,7 @@ struct pinctrl_dev *pinctrl_init_controller(struct pinctrl_desc *pctldesc, INIT_RADIX_TREE(&pctldev->pin_function_tree, GFP_KERNEL); #endif INIT_LIST_HEAD(&pctldev->gpio_ranges); + INIT_LIST_HEAD(&pctldev->node); pctldev->dev = dev; mutex_init(&pctldev->mutex); @@ -2089,7 +2090,6 @@ EXPORT_SYMBOL_GPL(pinctrl_register_and_init); void pinctrl_unregister(struct pinctrl_dev *pctldev) { struct pinctrl_gpio_range *range, *n; - struct pinctrl_dev *p, *p1; if (pctldev == NULL) return; @@ -2104,9 +2104,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) mutex_lock(&pinctrldev_list_mutex); mutex_lock(&pctldev->mutex); /* TODO: check that no pinmuxes are still active? */ - list_for_each_entry_safe(p, p1, &pinctrldev_list, node) - if (p == pctldev) - list_del(&p->node); + list_del(&pctldev->node); pinmux_generic_free_functions(pctldev); pinctrl_generic_free_groups(pctldev); /* Destroy descriptor tree */ From 49873e99b7b5d59eef238199fd55f8345e860824 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 13 Jan 2017 16:02:03 +0100 Subject: [PATCH 0371/1587] dmaengine: ste_dma40: indicate directions on channels Since the introduction of the .directions flags, ste_dma40 was never patched to indicate which transfer directions it can manage. This causes a problem when trying to use the dmaengine for generic ALSA SoC DMA: ux500-msp-i2s.1: Failed to get DMA channel capabilities, falling back to period counting: -6 This patch fixes this issue by indicating the supported transfer directions for slave and memcpy channels. Signed-off-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 8684d11b29bb..2f0852dfbd1b 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2809,12 +2809,14 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma, static void d40_ops_init(struct d40_base *base, struct dma_device *dev) { - if (dma_has_cap(DMA_SLAVE, dev->cap_mask)) + if (dma_has_cap(DMA_SLAVE, dev->cap_mask)) { dev->device_prep_slave_sg = d40_prep_slave_sg; + dev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + } if (dma_has_cap(DMA_MEMCPY, dev->cap_mask)) { dev->device_prep_dma_memcpy = d40_prep_memcpy; - + dev->directions = BIT(DMA_MEM_TO_MEM); /* * This controller can only access address at even * 32bit boundaries, i.e. 2^2 From 15c606686541d49cc38465a3cfe25c23bff4395b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 13 Jan 2017 16:02:09 +0100 Subject: [PATCH 0372/1587] dmaengine: ste_dma40: indicate granularity on channels The ste_dma40 has burst level granularity on the residue registers, which is necessary for some clients to know, notably the UART. Before this patch we get this message: uart-pl011 80007000.uart: RX DMA disabled - no residue processing This patch fixes it. Signed-off-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 2f0852dfbd1b..a6620b671d1d 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2838,6 +2838,7 @@ static void d40_ops_init(struct d40_base *base, struct dma_device *dev) dev->device_pause = d40_pause; dev->device_resume = d40_resume; dev->device_terminate_all = d40_terminate_all; + dev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; dev->dev = base->dev; } From a7f6c1b63b863d29f126d9b163ad5b40008544b2 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 14 Nov 2016 20:11:52 +0900 Subject: [PATCH 0373/1587] AppArmor: Use GFP_KERNEL for __aa_kvmalloc(). Calling kmalloc(GFP_NOIO) with order == PAGE_ALLOC_COSTLY_ORDER is not recommended because it might fall into infinite retry loop without invoking the OOM killer. Since aa_dfa_unpack() is the only caller of kvzalloc() and aa_dfa_unpack() which is calling kvzalloc() via unpack_table() is doing kzalloc(GFP_KERNEL), it is safe to use GFP_KERNEL from __aa_kvmalloc(). Since aa_simple_write_to_buffer() is the only caller of kvmalloc() and aa_simple_write_to_buffer() is calling copy_from_user() which is GFP_KERNEL context (see memdup_user_nul()), it is safe to use GFP_KERNEL from __aa_kvmalloc(). Therefore, replace GFP_NOIO with GFP_KERNEL. Also, since we have vmalloc() fallback, add __GFP_NORETRY so that we don't invoke the OOM killer by kmalloc(GFP_KERNEL) with order == PAGE_ALLOC_COSTLY_ORDER. Signed-off-by: Tetsuo Handa Signed-off-by: John Johansen --- security/apparmor/lib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index c1827e068454..2ef422a25474 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -95,7 +95,8 @@ void *__aa_kvmalloc(size_t size, gfp_t flags) /* do not attempt kmalloc if we need more than 16 pages at once */ if (size <= (16*PAGE_SIZE)) - buffer = kmalloc(size, flags | GFP_NOIO | __GFP_NOWARN); + buffer = kmalloc(size, flags | GFP_KERNEL | __GFP_NORETRY | + __GFP_NOWARN); if (!buffer) { if (flags & __GFP_ZERO) buffer = vzalloc(size); From d7969f5976a35b48ba4eb60aaad73535f1792019 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Jan 2017 14:36:16 +0100 Subject: [PATCH 0374/1587] ahci: imx: fix building without hwmon or thermal When CONFIG_HWMON is disabled, we now get a link failure: ERROR: "devm_hwmon_device_register_with_groups" [drivers/ata/ahci_imx.ko] undefined! drivers/ata/ahci_imx.o: In function `imx_ahci_probe': ahci_imx.c:(.text.imx_ahci_probe+0x304): undefined reference to `devm_thermal_zone_of_sensor_register' This makes the code calling into the hwmon subsystem compile-time conditional, and adds a Kconfig dependency to avoid the corner case of having HWMON=m and AHCI_IMX=y, by forcing AHCI_IMX=m in this case. The thermal subsystem already has a check in its header, but that also doesn't cover the THERMAL=m case, so we need a somewhat complex Kconfig expression to handle all cases. Fixes: 54643a83b41a ("ahci: imx: Add imx53 SATA temperature sensor support") Signed-off-by: Arnd Bergmann Acked-by: Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 1 + drivers/ata/ahci_imx.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 78c002021029..70b57d2229d6 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -129,6 +129,7 @@ config AHCI_ST config AHCI_IMX tristate "Freescale i.MX AHCI SATA support" depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST) + depends on (HWMON && (THERMAL || !THERMAL_OF)) || !HWMON help This option enables support for the Freescale i.MX SoC's onboard AHCI SATA. diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 420f065978dc..787567e840bd 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -774,7 +774,8 @@ static int imx_ahci_probe(struct platform_device *pdev) if (ret) return ret; - if (imxpriv->type == AHCI_IMX53) { + if (imxpriv->type == AHCI_IMX53 && + IS_ENABLED(CONFIG_HWMON)) { /* Add the temperature monitor */ struct device *hwmon_dev; From 8486adf0d755062611968ecc1632a13ebce71660 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Dec 2016 17:04:13 -0800 Subject: [PATCH 0375/1587] apparmor: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Signed-off-by: John Johansen --- security/apparmor/file.c | 4 ++-- security/apparmor/lsm.c | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 4d2af4b01033..608971ac6781 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -349,8 +349,8 @@ static inline bool xindex_is_subset(u32 link, u32 target) int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry) { - struct path link = { new_dir->mnt, new_dentry }; - struct path target = { new_dir->mnt, old_dentry }; + struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry }; + struct path target = { .mnt = new_dir->mnt, .dentry = old_dentry }; struct path_cond cond = { d_backing_inode(old_dentry)->i_uid, d_backing_inode(old_dentry)->i_mode diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 41b8cb115801..f76738b1eb15 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -176,7 +176,7 @@ static int common_perm_dir_dentry(int op, const struct path *dir, struct dentry *dentry, u32 mask, struct path_cond *cond) { - struct path path = { dir->mnt, dentry }; + struct path path = { .mnt = dir->mnt, .dentry = dentry }; return common_perm(op, &path, mask, cond); } @@ -306,8 +306,10 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d profile = aa_current_profile(); if (!unconfined(profile)) { - struct path old_path = { old_dir->mnt, old_dentry }; - struct path new_path = { new_dir->mnt, new_dentry }; + struct path old_path = { .mnt = old_dir->mnt, + .dentry = old_dentry }; + struct path new_path = { .mnt = new_dir->mnt, + .dentry = new_dentry }; struct path_cond cond = { d_backing_inode(old_dentry)->i_uid, d_backing_inode(old_dentry)->i_mode }; From 12557dcba21b015f470076da6947e68bc70fff64 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:13 -0800 Subject: [PATCH 0376/1587] apparmor: move lib definitions into separate lib include Signed-off-by: John Johansen --- security/apparmor/include/apparmor.h | 82 +----------------------- security/apparmor/include/lib.h | 94 ++++++++++++++++++++++++++++ security/apparmor/include/policy.h | 1 + security/apparmor/lib.c | 2 +- security/apparmor/match.c | 2 +- 5 files changed, 99 insertions(+), 82 deletions(-) create mode 100644 security/apparmor/include/lib.h diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 5d721e990876..1750cc0721c1 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -1,7 +1,7 @@ /* * AppArmor security module * - * This file contains AppArmor basic global and lib definitions + * This file contains AppArmor basic global * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. @@ -15,10 +15,7 @@ #ifndef __APPARMOR_H #define __APPARMOR_H -#include -#include - -#include "match.h" +#include /* * Class of mediation types in the AppArmor policy db @@ -43,79 +40,4 @@ extern bool aa_g_logsyscall; extern bool aa_g_paranoid_load; extern unsigned int aa_g_path_max; -/* - * DEBUG remains global (no per profile flag) since it is mostly used in sysctl - * which is not related to profile accesses. - */ - -#define AA_DEBUG(fmt, args...) \ - do { \ - if (aa_g_debug && printk_ratelimit()) \ - printk(KERN_DEBUG "AppArmor: " fmt, ##args); \ - } while (0) - -#define AA_ERROR(fmt, args...) \ - do { \ - if (printk_ratelimit()) \ - printk(KERN_ERR "AppArmor: " fmt, ##args); \ - } while (0) - -/* Flag indicating whether initialization completed */ -extern int apparmor_initialized __initdata; - -/* fn's in lib */ -char *aa_split_fqname(char *args, char **ns_name); -void aa_info_message(const char *str); -void *__aa_kvmalloc(size_t size, gfp_t flags); - -static inline void *kvmalloc(size_t size) -{ - return __aa_kvmalloc(size, 0); -} - -static inline void *kvzalloc(size_t size) -{ - return __aa_kvmalloc(size, __GFP_ZERO); -} - -/* returns 0 if kref not incremented */ -static inline int kref_get_not0(struct kref *kref) -{ - return atomic_inc_not_zero(&kref->refcount); -} - -/** - * aa_strneq - compare null terminated @str to a non null terminated substring - * @str: a null terminated string - * @sub: a substring, not necessarily null terminated - * @len: length of @sub to compare - * - * The @str string must be full consumed for this to be considered a match - */ -static inline bool aa_strneq(const char *str, const char *sub, int len) -{ - return !strncmp(str, sub, len) && !str[len]; -} - -/** - * aa_dfa_null_transition - step to next state after null character - * @dfa: the dfa to match against - * @start: the state of the dfa to start matching in - * - * aa_dfa_null_transition transitions to the next state after a null - * character which is not used in standard matching and is only - * used to separate pairs. - */ -static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, - unsigned int start) -{ - /* the null transition only needs the string's null terminator byte */ - return aa_dfa_next(dfa, start, 0); -} - -static inline bool mediated_filesystem(struct dentry *dentry) -{ - return !(dentry->d_sb->s_flags & MS_NOUSER); -} - #endif /* __APPARMOR_H */ diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h new file mode 100644 index 000000000000..71fd6d28a651 --- /dev/null +++ b/security/apparmor/include/lib.h @@ -0,0 +1,94 @@ +/* + * AppArmor security module + * + * This file contains AppArmor lib definitions + * + * 2017 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#ifndef __AA_LIB_H +#define __AA_LIB_H + +#include +#include + +#include "match.h" + +/* + * DEBUG remains global (no per profile flag) since it is mostly used in sysctl + * which is not related to profile accesses. + */ + +#define AA_DEBUG(fmt, args...) \ + do { \ + if (aa_g_debug) \ + pr_debug_ratelimited("AppArmor: " fmt, ##args); \ + } while (0) + +#define AA_ERROR(fmt, args...) \ + pr_err_ratelimited("AppArmor: " fmt, ##args) + +/* Flag indicating whether initialization completed */ +extern int apparmor_initialized __initdata; + +/* fn's in lib */ +char *aa_split_fqname(char *args, char **ns_name); +void aa_info_message(const char *str); +void *__aa_kvmalloc(size_t size, gfp_t flags); + +static inline void *kvmalloc(size_t size) +{ + return __aa_kvmalloc(size, 0); +} + +static inline void *kvzalloc(size_t size) +{ + return __aa_kvmalloc(size, __GFP_ZERO); +} + +/* returns 0 if kref not incremented */ +static inline int kref_get_not0(struct kref *kref) +{ + return atomic_inc_not_zero(&kref->refcount); +} + +/** + * aa_strneq - compare null terminated @str to a non null terminated substring + * @str: a null terminated string + * @sub: a substring, not necessarily null terminated + * @len: length of @sub to compare + * + * The @str string must be full consumed for this to be considered a match + */ +static inline bool aa_strneq(const char *str, const char *sub, int len) +{ + return !strncmp(str, sub, len) && !str[len]; +} + +/** + * aa_dfa_null_transition - step to next state after null character + * @dfa: the dfa to match against + * @start: the state of the dfa to start matching in + * + * aa_dfa_null_transition transitions to the next state after a null + * character which is not used in standard matching and is only + * used to separate pairs. + */ +static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, + unsigned int start) +{ + /* the null transition only needs the string's null terminator byte */ + return aa_dfa_next(dfa, start, 0); +} + +static inline bool mediated_filesystem(struct dentry *dentry) +{ + return !(dentry->d_sb->s_flags & MS_NOUSER); +} + +#endif /* AA_LIB_H */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 52275f040a5f..190fe37ecff0 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -27,6 +27,7 @@ #include "capability.h" #include "domain.h" #include "file.h" +#include "lib.h" #include "resource.h" extern const char *const aa_profile_mode_names[]; diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 2ef422a25474..6028ffc008ae 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -19,7 +19,7 @@ #include "include/audit.h" #include "include/apparmor.h" - +#include "include/lib.h" /** * aa_split_fqname - split a fqname into a profile and namespace name diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 3f900fcca8fb..0e04bcf91154 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -20,7 +20,7 @@ #include #include -#include "include/apparmor.h" +#include "include/lib.h" #include "include/match.h" #define base_idx(X) ((X) & 0xffffff) From fe6bb31f590c9cd9c8d3ddbdfd4301f72db91718 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:14 -0800 Subject: [PATCH 0377/1587] apparmor: split out shared policy_XXX fns to lib Signed-off-by: John Johansen --- security/apparmor/include/lib.h | 81 +++++++++++++++++++ security/apparmor/include/policy.h | 13 --- security/apparmor/lib.c | 52 ++++++++++++ security/apparmor/policy.c | 123 +---------------------------- 4 files changed, 137 insertions(+), 132 deletions(-) diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 71fd6d28a651..74cc68ea4c12 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -91,4 +91,85 @@ static inline bool mediated_filesystem(struct dentry *dentry) return !(dentry->d_sb->s_flags & MS_NOUSER); } +/* struct aa_policy - common part of both namespaces and profiles + * @name: name of the object + * @hname - The hierarchical name + * @list: list policy object is on + * @profiles: head of the profiles list contained in the object + */ +struct aa_policy { + char *name; + char *hname; + struct list_head list; + struct list_head profiles; +}; + +/** + * hname_tail - find the last component of an hname + * @name: hname to find the base profile name component of (NOT NULL) + * + * Returns: the tail (base profile name) name component of an hname + */ +static inline const char *hname_tail(const char *hname) +{ + char *split; + + hname = strim((char *)hname); + for (split = strstr(hname, "//"); split; split = strstr(hname, "//")) + hname = split + 2; + + return hname; +} + +/** + * __policy_find - find a policy by @name on a policy list + * @head: list to search (NOT NULL) + * @name: name to search for (NOT NULL) + * + * Requires: rcu_read_lock be held + * + * Returns: unrefcounted policy that match @name or NULL if not found + */ +static inline struct aa_policy *__policy_find(struct list_head *head, + const char *name) +{ + struct aa_policy *policy; + + list_for_each_entry_rcu(policy, head, list) { + if (!strcmp(policy->name, name)) + return policy; + } + return NULL; +} + +/** + * __policy_strn_find - find a policy that's name matches @len chars of @str + * @head: list to search (NOT NULL) + * @str: string to search for (NOT NULL) + * @len: length of match required + * + * Requires: rcu_read_lock be held + * + * Returns: unrefcounted policy that match @str or NULL if not found + * + * if @len == strlen(@strlen) then this is equiv to __policy_find + * other wise it allows searching for policy by a partial match of name + */ +static inline struct aa_policy *__policy_strn_find(struct list_head *head, + const char *str, int len) +{ + struct aa_policy *policy; + + list_for_each_entry_rcu(policy, head, list) { + if (aa_strneq(policy->name, str, len)) + return policy; + } + + return NULL; +} + +bool aa_policy_init(struct aa_policy *policy, const char *prefix, + const char *name); +void aa_policy_destroy(struct aa_policy *policy); + #endif /* AA_LIB_H */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 190fe37ecff0..9b199678a11c 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -77,19 +77,6 @@ enum profile_flags { struct aa_profile; -/* struct aa_policy - common part of both namespaces and profiles - * @name: name of the object - * @hname - The hierarchical name - * @list: list policy object is on - * @profiles: head of the profiles list contained in the object - */ -struct aa_policy { - char *name; - char *hname; - struct list_head list; - struct list_head profiles; -}; - /* struct aa_ns_acct - accounting of profiles in namespace * @max_size: maximum space allowed for all profiles in namespace * @max_count: maximum number of profiles that can be in this namespace diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 6028ffc008ae..e29ccdb0309a 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -20,6 +20,7 @@ #include "include/audit.h" #include "include/apparmor.h" #include "include/lib.h" +#include "include/policy.h" /** * aa_split_fqname - split a fqname into a profile and namespace name @@ -105,3 +106,54 @@ void *__aa_kvmalloc(size_t size, gfp_t flags) } return buffer; } + +/** + * aa_policy_init - initialize a policy structure + * @policy: policy to initialize (NOT NULL) + * @prefix: prefix name if any is required. (MAYBE NULL) + * @name: name of the policy, init will make a copy of it (NOT NULL) + * + * Note: this fn creates a copy of strings passed in + * + * Returns: true if policy init successful + */ +bool aa_policy_init(struct aa_policy *policy, const char *prefix, + const char *name) +{ + /* freed by policy_free */ + if (prefix) { + policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, + GFP_KERNEL); + if (policy->hname) + sprintf(policy->hname, "%s//%s", prefix, name); + } else + policy->hname = kstrdup(name, GFP_KERNEL); + if (!policy->hname) + return 0; + /* base.name is a substring of fqname */ + policy->name = (char *)hname_tail(policy->hname); + INIT_LIST_HEAD(&policy->list); + INIT_LIST_HEAD(&policy->profiles); + + return 1; +} + +/** + * aa_policy_destroy - free the elements referenced by @policy + * @policy: policy that is to have its elements freed (NOT NULL) + */ +void aa_policy_destroy(struct aa_policy *policy) +{ + /* still contains profiles -- invalid */ + if (on_list_rcu(&policy->profiles)) { + AA_ERROR("%s: internal error, policy '%s' contains profiles\n", + __func__, policy->name); + } + if (on_list_rcu(&policy->list)) { + AA_ERROR("%s: internal error, policy '%s' still on list\n", + __func__, policy->name); + } + + /* don't free name as its a subset of hname */ + kzfree(policy->hname); +} diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 179e68d7dc5f..a331149a4587 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -99,121 +99,6 @@ const char *const aa_profile_mode_names[] = { "unconfined", }; -/** - * hname_tail - find the last component of an hname - * @name: hname to find the base profile name component of (NOT NULL) - * - * Returns: the tail (base profile name) name component of an hname - */ -static const char *hname_tail(const char *hname) -{ - char *split; - hname = strim((char *)hname); - for (split = strstr(hname, "//"); split; split = strstr(hname, "//")) - hname = split + 2; - - return hname; -} - -/** - * policy_init - initialize a policy structure - * @policy: policy to initialize (NOT NULL) - * @prefix: prefix name if any is required. (MAYBE NULL) - * @name: name of the policy, init will make a copy of it (NOT NULL) - * - * Note: this fn creates a copy of strings passed in - * - * Returns: true if policy init successful - */ -static bool policy_init(struct aa_policy *policy, const char *prefix, - const char *name) -{ - /* freed by policy_free */ - if (prefix) { - policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, - GFP_KERNEL); - if (policy->hname) - sprintf(policy->hname, "%s//%s", prefix, name); - } else - policy->hname = kstrdup(name, GFP_KERNEL); - if (!policy->hname) - return 0; - /* base.name is a substring of fqname */ - policy->name = (char *)hname_tail(policy->hname); - INIT_LIST_HEAD(&policy->list); - INIT_LIST_HEAD(&policy->profiles); - - return 1; -} - -/** - * policy_destroy - free the elements referenced by @policy - * @policy: policy that is to have its elements freed (NOT NULL) - */ -static void policy_destroy(struct aa_policy *policy) -{ - /* still contains profiles -- invalid */ - if (on_list_rcu(&policy->profiles)) { - AA_ERROR("%s: internal error, " - "policy '%s' still contains profiles\n", - __func__, policy->name); - BUG(); - } - if (on_list_rcu(&policy->list)) { - AA_ERROR("%s: internal error, policy '%s' still on list\n", - __func__, policy->name); - BUG(); - } - - /* don't free name as its a subset of hname */ - kzfree(policy->hname); -} - -/** - * __policy_find - find a policy by @name on a policy list - * @head: list to search (NOT NULL) - * @name: name to search for (NOT NULL) - * - * Requires: rcu_read_lock be held - * - * Returns: unrefcounted policy that match @name or NULL if not found - */ -static struct aa_policy *__policy_find(struct list_head *head, const char *name) -{ - struct aa_policy *policy; - - list_for_each_entry_rcu(policy, head, list) { - if (!strcmp(policy->name, name)) - return policy; - } - return NULL; -} - -/** - * __policy_strn_find - find a policy that's name matches @len chars of @str - * @head: list to search (NOT NULL) - * @str: string to search for (NOT NULL) - * @len: length of match required - * - * Requires: rcu_read_lock be held - * - * Returns: unrefcounted policy that match @str or NULL if not found - * - * if @len == strlen(@strlen) then this is equiv to __policy_find - * other wise it allows searching for policy by a partial match of name - */ -static struct aa_policy *__policy_strn_find(struct list_head *head, - const char *str, int len) -{ - struct aa_policy *policy; - - list_for_each_entry_rcu(policy, head, list) { - if (aa_strneq(policy->name, str, len)) - return policy; - } - - return NULL; -} /* * Routines for AppArmor namespaces @@ -280,7 +165,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, AA_DEBUG("%s(%p)\n", __func__, ns); if (!ns) return NULL; - if (!policy_init(&ns->base, prefix, name)) + if (!aa_policy_init(&ns->base, prefix, name)) goto fail_ns; INIT_LIST_HEAD(&ns->sub_ns); @@ -321,7 +206,7 @@ static void free_namespace(struct aa_namespace *ns) if (!ns) return; - policy_destroy(&ns->base); + aa_policy_destroy(&ns->base); aa_put_namespace(ns->parent); ns->unconfined->ns = NULL; @@ -595,7 +480,7 @@ void aa_free_profile(struct aa_profile *profile) return; /* free children profiles */ - policy_destroy(&profile->base); + aa_policy_destroy(&profile->base); aa_put_profile(rcu_access_pointer(profile->parent)); aa_put_namespace(profile->ns); @@ -657,7 +542,7 @@ struct aa_profile *aa_alloc_profile(const char *hname) goto fail; kref_init(&profile->replacedby->count); - if (!policy_init(&profile->base, NULL, hname)) + if (!aa_policy_init(&profile->base, NULL, hname)) goto fail; kref_init(&profile->count); From cff281f6861e72f1416927aaa0c10a08bb7b2d3f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:15 -0800 Subject: [PATCH 0378/1587] apparmor: split apparmor policy namespaces code into its own file Policy namespaces will be diverging from profile management and expanding so put it in its own file. Signed-off-by: John Johansen --- security/apparmor/Makefile | 2 +- security/apparmor/apparmorfs.c | 1 + security/apparmor/audit.c | 1 + security/apparmor/domain.c | 1 + security/apparmor/include/policy.h | 112 +--------- security/apparmor/include/policy_ns.h | 137 ++++++++++++ security/apparmor/lsm.c | 1 + security/apparmor/policy.c | 298 ++------------------------ security/apparmor/policy_ns.c | 291 +++++++++++++++++++++++++ security/apparmor/procattr.c | 1 + 10 files changed, 454 insertions(+), 391 deletions(-) create mode 100644 security/apparmor/include/policy_ns.h create mode 100644 security/apparmor/policy_ns.c diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index d693df874818..3485f49d9de9 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ - resource.o sid.o file.o + resource.o sid.o file.o policy_ns.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o clean-files := capability_names.h rlim_names.h diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 5923d5665209..efac1a9565e2 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -28,6 +28,7 @@ #include "include/context.h" #include "include/crypto.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/resource.h" /** diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 3a7f1da1425e..42101c42f446 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -18,6 +18,7 @@ #include "include/apparmor.h" #include "include/audit.h" #include "include/policy.h" +#include "include/policy_ns.h" const char *const op_table[] = { "null", diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index a4d90aa1045a..02d2f01e908d 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -29,6 +29,7 @@ #include "include/match.h" #include "include/path.h" #include "include/policy.h" +#include "include/policy_ns.h" /** * aa_free_domain_entries - free entries in a domain table diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 9b199678a11c..a1b1d8ab589c 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -30,6 +30,9 @@ #include "lib.h" #include "resource.h" + +struct aa_namespace; + extern const char *const aa_profile_mode_names[]; #define APPARMOR_MODE_NAMES_MAX_INDEX 4 @@ -77,57 +80,6 @@ enum profile_flags { struct aa_profile; -/* struct aa_ns_acct - accounting of profiles in namespace - * @max_size: maximum space allowed for all profiles in namespace - * @max_count: maximum number of profiles that can be in this namespace - * @size: current size of profiles - * @count: current count of profiles (includes null profiles) - */ -struct aa_ns_acct { - int max_size; - int max_count; - int size; - int count; -}; - -/* struct aa_namespace - namespace for a set of profiles - * @base: common policy - * @parent: parent of namespace - * @lock: lock for modifying the object - * @acct: accounting for the namespace - * @unconfined: special unconfined profile for the namespace - * @sub_ns: list of namespaces under the current namespace. - * @uniq_null: uniq value used for null learning profiles - * @uniq_id: a unique id count for the profiles in the namespace - * @dents: dentries for the namespaces file entries in apparmorfs - * - * An aa_namespace defines the set profiles that are searched to determine - * which profile to attach to a task. Profiles can not be shared between - * aa_namespaces and profile names within a namespace are guaranteed to be - * unique. When profiles in separate namespaces have the same name they - * are NOT considered to be equivalent. - * - * Namespaces are hierarchical and only namespaces and profiles below the - * current namespace are visible. - * - * Namespace names must be unique and can not contain the characters :/\0 - * - * FIXME TODO: add vserver support of namespaces (can it all be done in - * userspace?) - */ -struct aa_namespace { - struct aa_policy base; - struct aa_namespace *parent; - struct mutex lock; - struct aa_ns_acct acct; - struct aa_profile *unconfined; - struct list_head sub_ns; - atomic_t uniq_null; - long uniq_id; - - struct dentry *dents[AAFS_NS_SIZEOF]; -}; - /* struct aa_policydb - match engine for a policy * dfa: dfa pattern match * start: set of start states for the different classes of data @@ -212,20 +164,12 @@ struct aa_profile { struct dentry *dents[AAFS_PROF_SIZEOF]; }; -extern struct aa_namespace *root_ns; extern enum profile_mode aa_g_profile_mode; +void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new); + void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view); -const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child); -int aa_alloc_root_ns(void); -void aa_free_root_ns(void); -void aa_free_namespace_kref(struct kref *kref); - -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name); - void aa_free_replacedby_kref(struct kref *kref); struct aa_profile *aa_alloc_profile(const char *name); @@ -238,6 +182,7 @@ struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name); ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); ssize_t aa_remove_profiles(char *name, size_t size); +void __aa_profile_list_release(struct list_head *head); #define PROF_ADD 1 #define PROF_REPLACE 0 @@ -245,12 +190,6 @@ ssize_t aa_remove_profiles(char *name, size_t size); #define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) -static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) -{ - return rcu_dereference_protected(p->parent, - mutex_is_locked(&p->ns->lock)); -} - /** * aa_get_profile - increment refcount on profile @p * @p: profile (MAYBE NULL) @@ -344,45 +283,6 @@ static inline void aa_put_replacedby(struct aa_replacedby *p) kref_put(&p->count, aa_free_replacedby_kref); } -/* requires profile list write lock held */ -static inline void __aa_update_replacedby(struct aa_profile *orig, - struct aa_profile *new) -{ - struct aa_profile *tmp; - tmp = rcu_dereference_protected(orig->replacedby->profile, - mutex_is_locked(&orig->ns->lock)); - rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); - orig->flags |= PFLAG_INVALID; - aa_put_profile(tmp); -} - -/** - * aa_get_namespace - increment references count on @ns - * @ns: namespace to increment reference count of (MAYBE NULL) - * - * Returns: pointer to @ns, if @ns is NULL returns NULL - * Requires: @ns must be held with valid refcount when called - */ -static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) -{ - if (ns) - aa_get_profile(ns->unconfined); - - return ns; -} - -/** - * aa_put_namespace - decrement refcount on @ns - * @ns: namespace to put reference of - * - * Decrement reference count of @ns and if no longer in use free it - */ -static inline void aa_put_namespace(struct aa_namespace *ns) -{ - if (ns) - aa_put_profile(ns->unconfined); -} - static inline int AUDIT_MODE(struct aa_profile *profile) { if (aa_g_audit != AUDIT_NORMAL) diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h new file mode 100644 index 000000000000..4b9e8c7c669a --- /dev/null +++ b/security/apparmor/include/policy_ns.h @@ -0,0 +1,137 @@ +/* + * AppArmor security module + * + * This file contains AppArmor policy definitions. + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2017 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#ifndef __AA_NAMESPACE_H +#define __AA_NAMESPACE_H + +#include + +#include "apparmor.h" +#include "apparmorfs.h" +#include "policy.h" + + +/* struct aa_ns_acct - accounting of profiles in namespace + * @max_size: maximum space allowed for all profiles in namespace + * @max_count: maximum number of profiles that can be in this namespace + * @size: current size of profiles + * @count: current count of profiles (includes null profiles) + */ +struct aa_ns_acct { + int max_size; + int max_count; + int size; + int count; +}; + +/* struct aa_namespace - namespace for a set of profiles + * @base: common policy + * @parent: parent of namespace + * @lock: lock for modifying the object + * @acct: accounting for the namespace + * @unconfined: special unconfined profile for the namespace + * @sub_ns: list of namespaces under the current namespace. + * @uniq_null: uniq value used for null learning profiles + * @uniq_id: a unique id count for the profiles in the namespace + * @dents: dentries for the namespaces file entries in apparmorfs + * + * An aa_namespace defines the set profiles that are searched to determine + * which profile to attach to a task. Profiles can not be shared between + * aa_namespaces and profile names within a namespace are guaranteed to be + * unique. When profiles in separate namespaces have the same name they + * are NOT considered to be equivalent. + * + * Namespaces are hierarchical and only namespaces and profiles below the + * current namespace are visible. + * + * Namespace names must be unique and can not contain the characters :/\0 + */ +struct aa_namespace { + struct aa_policy base; + struct aa_namespace *parent; + struct mutex lock; + struct aa_ns_acct acct; + struct aa_profile *unconfined; + struct list_head sub_ns; + atomic_t uniq_null; + long uniq_id; + + struct dentry *dents[AAFS_NS_SIZEOF]; +}; + +extern struct aa_namespace *root_ns; + +extern const char *aa_hidden_ns_name; + +bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view); +const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child); +void aa_free_namespace(struct aa_namespace *ns); +int aa_alloc_root_ns(void); +void aa_free_root_ns(void); +void aa_free_namespace_kref(struct kref *kref); + +struct aa_namespace *aa_find_namespace(struct aa_namespace *root, + const char *name); +struct aa_namespace *aa_prepare_namespace(const char *name); +void __aa_remove_namespace(struct aa_namespace *ns); + +static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) +{ + return rcu_dereference_protected(p->parent, + mutex_is_locked(&p->ns->lock)); +} + +/** + * aa_get_namespace - increment references count on @ns + * @ns: namespace to increment reference count of (MAYBE NULL) + * + * Returns: pointer to @ns, if @ns is NULL returns NULL + * Requires: @ns must be held with valid refcount when called + */ +static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) +{ + if (ns) + aa_get_profile(ns->unconfined); + + return ns; +} + +/** + * aa_put_namespace - decrement refcount on @ns + * @ns: namespace to put reference of + * + * Decrement reference count of @ns and if no longer in use free it + */ +static inline void aa_put_namespace(struct aa_namespace *ns) +{ + if (ns) + aa_put_profile(ns->unconfined); +} + +/** + * __aa_find_namespace - find a namespace on a list by @name + * @head: list to search for namespace on (NOT NULL) + * @name: name of namespace to look for (NOT NULL) + * + * Returns: unrefcounted namespace + * + * Requires: rcu_read_lock be held + */ +static inline struct aa_namespace *__aa_find_namespace(struct list_head *head, + const char *name) +{ + return (struct aa_namespace *)__policy_find(head, name); +} + +#endif /* AA_NAMESPACE_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f76738b1eb15..1dae66ba757b 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -34,6 +34,7 @@ #include "include/ipc.h" #include "include/path.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/procattr.h" /* Flag indicating whether initialization completed */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index a331149a4587..2a861824319e 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -85,13 +85,11 @@ #include "include/match.h" #include "include/path.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/policy_unpack.h" #include "include/resource.h" -/* root profile namespace */ -struct aa_namespace *root_ns; - const char *const aa_profile_mode_names[] = { "enforce", "complain", @@ -100,202 +98,16 @@ const char *const aa_profile_mode_names[] = { }; -/* - * Routines for AppArmor namespaces - */ - -static const char *hidden_ns_name = "---"; -/** - * aa_ns_visible - test if @view is visible from @curr - * @curr: namespace to treat as the parent (NOT NULL) - * @view: namespace to test if visible from @curr (NOT NULL) - * - * Returns: true if @view is visible from @curr else false - */ -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) +/* requires profile list write lock held */ +void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new) { - if (curr == view) - return true; + struct aa_profile *tmp; - for ( ; view; view = view->parent) { - if (view->parent == curr) - return true; - } - return false; -} - -/** - * aa_na_name - Find the ns name to display for @view from @curr - * @curr - current namespace (NOT NULL) - * @view - namespace attempting to view (NOT NULL) - * - * Returns: name of @view visible from @curr - */ -const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) -{ - /* if view == curr then the namespace name isn't displayed */ - if (curr == view) - return ""; - - if (aa_ns_visible(curr, view)) { - /* at this point if a ns is visible it is in a view ns - * thus the curr ns.hname is a prefix of its name. - * Only output the virtualized portion of the name - * Add + 2 to skip over // separating curr hname prefix - * from the visible tail of the views hname - */ - return view->base.hname + strlen(curr->base.hname) + 2; - } else - return hidden_ns_name; -} - -/** - * alloc_namespace - allocate, initialize and return a new namespace - * @prefix: parent namespace name (MAYBE NULL) - * @name: a preallocated name (NOT NULL) - * - * Returns: refcounted namespace or NULL on failure. - */ -static struct aa_namespace *alloc_namespace(const char *prefix, - const char *name) -{ - struct aa_namespace *ns; - - ns = kzalloc(sizeof(*ns), GFP_KERNEL); - AA_DEBUG("%s(%p)\n", __func__, ns); - if (!ns) - return NULL; - if (!aa_policy_init(&ns->base, prefix, name)) - goto fail_ns; - - INIT_LIST_HEAD(&ns->sub_ns); - mutex_init(&ns->lock); - - /* released by free_namespace */ - ns->unconfined = aa_alloc_profile("unconfined"); - if (!ns->unconfined) - goto fail_unconfined; - - ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR | - PFLAG_IMMUTABLE | PFLAG_NS_COUNT; - ns->unconfined->mode = APPARMOR_UNCONFINED; - - /* ns and ns->unconfined share ns->unconfined refcount */ - ns->unconfined->ns = ns; - - atomic_set(&ns->uniq_null, 0); - - return ns; - -fail_unconfined: - kzfree(ns->base.hname); -fail_ns: - kzfree(ns); - return NULL; -} - -/** - * free_namespace - free a profile namespace - * @ns: the namespace to free (MAYBE NULL) - * - * Requires: All references to the namespace must have been put, if the - * namespace was referenced by a profile confining a task, - */ -static void free_namespace(struct aa_namespace *ns) -{ - if (!ns) - return; - - aa_policy_destroy(&ns->base); - aa_put_namespace(ns->parent); - - ns->unconfined->ns = NULL; - aa_free_profile(ns->unconfined); - kzfree(ns); -} - -/** - * __aa_find_namespace - find a namespace on a list by @name - * @head: list to search for namespace on (NOT NULL) - * @name: name of namespace to look for (NOT NULL) - * - * Returns: unrefcounted namespace - * - * Requires: rcu_read_lock be held - */ -static struct aa_namespace *__aa_find_namespace(struct list_head *head, - const char *name) -{ - return (struct aa_namespace *)__policy_find(head, name); -} - -/** - * aa_find_namespace - look up a profile namespace on the namespace list - * @root: namespace to search in (NOT NULL) - * @name: name of namespace to find (NOT NULL) - * - * Returns: a refcounted namespace on the list, or NULL if no namespace - * called @name exists. - * - * refcount released by caller - */ -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name) -{ - struct aa_namespace *ns = NULL; - - rcu_read_lock(); - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); - rcu_read_unlock(); - - return ns; -} - -/** - * aa_prepare_namespace - find an existing or create a new namespace of @name - * @name: the namespace to find or add (MAYBE NULL) - * - * Returns: refcounted namespace or NULL if failed to create one - */ -static struct aa_namespace *aa_prepare_namespace(const char *name) -{ - struct aa_namespace *ns, *root; - - root = aa_current_profile()->ns; - - mutex_lock(&root->lock); - - /* if name isn't specified the profile is loaded to the current ns */ - if (!name) { - /* released by caller */ - ns = aa_get_namespace(root); - goto out; - } - - /* try and find the specified ns and if it doesn't exist create it */ - /* released by caller */ - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); - if (!ns) { - ns = alloc_namespace(root->base.hname, name); - if (!ns) - goto out; - if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) { - AA_ERROR("Failed to create interface for ns %s\n", - ns->base.name); - free_namespace(ns); - ns = NULL; - goto out; - } - ns->parent = aa_get_namespace(root); - list_add_rcu(&ns->base.list, &root->sub_ns); - /* add list ref */ - aa_get_namespace(ns); - } -out: - mutex_unlock(&root->lock); - - /* return ref */ - return ns; + tmp = rcu_dereference_protected(orig->replacedby->profile, + mutex_is_locked(&orig->ns->lock)); + rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); + orig->flags |= PFLAG_INVALID; + aa_put_profile(tmp); } /** @@ -333,8 +145,6 @@ static void __list_remove_profile(struct aa_profile *profile) aa_put_profile(profile); } -static void __profile_list_release(struct list_head *head); - /** * __remove_profile - remove old profile, and children * @profile: profile to be replaced (NOT NULL) @@ -344,7 +154,7 @@ static void __profile_list_release(struct list_head *head); static void __remove_profile(struct aa_profile *profile) { /* release any children lists first */ - __profile_list_release(&profile->base.profiles); + __aa_profile_list_release(&profile->base.profiles); /* released by free_profile */ __aa_update_replacedby(profile, profile->ns->unconfined); __aa_fs_profile_rmdir(profile); @@ -352,98 +162,18 @@ static void __remove_profile(struct aa_profile *profile) } /** - * __profile_list_release - remove all profiles on the list and put refs + * __aa_profile_list_release - remove all profiles on the list and put refs * @head: list of profiles (NOT NULL) * * Requires: namespace lock be held */ -static void __profile_list_release(struct list_head *head) +void __aa_profile_list_release(struct list_head *head) { struct aa_profile *profile, *tmp; list_for_each_entry_safe(profile, tmp, head, base.list) __remove_profile(profile); } -static void __ns_list_release(struct list_head *head); - -/** - * destroy_namespace - remove everything contained by @ns - * @ns: namespace to have it contents removed (NOT NULL) - */ -static void destroy_namespace(struct aa_namespace *ns) -{ - if (!ns) - return; - - mutex_lock(&ns->lock); - /* release all profiles in this namespace */ - __profile_list_release(&ns->base.profiles); - - /* release all sub namespaces */ - __ns_list_release(&ns->sub_ns); - - if (ns->parent) - __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); - __aa_fs_namespace_rmdir(ns); - mutex_unlock(&ns->lock); -} - -/** - * __remove_namespace - remove a namespace and all its children - * @ns: namespace to be removed (NOT NULL) - * - * Requires: ns->parent->lock be held and ns removed from parent. - */ -static void __remove_namespace(struct aa_namespace *ns) -{ - /* remove ns from namespace list */ - list_del_rcu(&ns->base.list); - destroy_namespace(ns); - aa_put_namespace(ns); -} - -/** - * __ns_list_release - remove all profile namespaces on the list put refs - * @head: list of profile namespaces (NOT NULL) - * - * Requires: namespace lock be held - */ -static void __ns_list_release(struct list_head *head) -{ - struct aa_namespace *ns, *tmp; - list_for_each_entry_safe(ns, tmp, head, base.list) - __remove_namespace(ns); - -} - -/** - * aa_alloc_root_ns - allocate the root profile namespace - * - * Returns: %0 on success else error - * - */ -int __init aa_alloc_root_ns(void) -{ - /* released by aa_free_root_ns - used as list ref*/ - root_ns = alloc_namespace(NULL, "root"); - if (!root_ns) - return -ENOMEM; - - return 0; -} - - /** - * aa_free_root_ns - free the root profile namespace - */ -void __init aa_free_root_ns(void) - { - struct aa_namespace *ns = root_ns; - root_ns = NULL; - - destroy_namespace(ns); - aa_put_namespace(ns); -} - static void free_replacedby(struct aa_replacedby *r) { @@ -507,7 +237,7 @@ static void aa_free_profile_rcu(struct rcu_head *head) { struct aa_profile *p = container_of(head, struct aa_profile, rcu); if (p->flags & PFLAG_NS_COUNT) - free_namespace(p->ns); + aa_free_namespace(p->ns); else aa_free_profile(p); } @@ -1181,7 +911,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) if (!name) { /* remove namespace - can only happen if fqname[0] == ':' */ mutex_lock(&ns->parent->lock); - __remove_namespace(ns); + __aa_remove_namespace(ns); mutex_unlock(&ns->parent->lock); } else { /* remove profile */ diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c new file mode 100644 index 000000000000..d4e9924a276e --- /dev/null +++ b/security/apparmor/policy_ns.c @@ -0,0 +1,291 @@ +/* + * AppArmor security module + * + * This file contains AppArmor policy manipulation functions + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2017 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor policy namespaces, allow for different sets of policies + * to be loaded for tasks within the namespace. + */ + +#include +#include +#include +#include + +#include "include/apparmor.h" +#include "include/context.h" +#include "include/policy_ns.h" +#include "include/policy.h" + +/* root profile namespace */ +struct aa_namespace *root_ns; +const char *aa_hidden_ns_name = "---"; + +/** + * aa_ns_visible - test if @view is visible from @curr + * @curr: namespace to treat as the parent (NOT NULL) + * @view: namespace to test if visible from @curr (NOT NULL) + * + * Returns: true if @view is visible from @curr else false + */ +bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) +{ + if (curr == view) + return true; + + for ( ; view; view = view->parent) { + if (view->parent == curr) + return true; + } + return false; +} + +/** + * aa_na_name - Find the ns name to display for @view from @curr + * @curr - current namespace (NOT NULL) + * @view - namespace attempting to view (NOT NULL) + * + * Returns: name of @view visible from @curr + */ +const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) +{ + /* if view == curr then the namespace name isn't displayed */ + if (curr == view) + return ""; + + if (aa_ns_visible(curr, view)) { + /* at this point if a ns is visible it is in a view ns + * thus the curr ns.hname is a prefix of its name. + * Only output the virtualized portion of the name + * Add + 2 to skip over // separating curr hname prefix + * from the visible tail of the views hname + */ + return view->base.hname + strlen(curr->base.hname) + 2; + } + + return aa_hidden_ns_name; +} + +/** + * alloc_namespace - allocate, initialize and return a new namespace + * @prefix: parent namespace name (MAYBE NULL) + * @name: a preallocated name (NOT NULL) + * + * Returns: refcounted namespace or NULL on failure. + */ +static struct aa_namespace *alloc_namespace(const char *prefix, + const char *name) +{ + struct aa_namespace *ns; + + ns = kzalloc(sizeof(*ns), GFP_KERNEL); + AA_DEBUG("%s(%p)\n", __func__, ns); + if (!ns) + return NULL; + if (!aa_policy_init(&ns->base, prefix, name)) + goto fail_ns; + + INIT_LIST_HEAD(&ns->sub_ns); + mutex_init(&ns->lock); + + /* released by free_namespace */ + ns->unconfined = aa_alloc_profile("unconfined"); + if (!ns->unconfined) + goto fail_unconfined; + + ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR | + PFLAG_IMMUTABLE | PFLAG_NS_COUNT; + ns->unconfined->mode = APPARMOR_UNCONFINED; + + /* ns and ns->unconfined share ns->unconfined refcount */ + ns->unconfined->ns = ns; + + atomic_set(&ns->uniq_null, 0); + + return ns; + +fail_unconfined: + kzfree(ns->base.hname); +fail_ns: + kzfree(ns); + return NULL; +} + +/** + * aa_free_namespace - free a profile namespace + * @ns: the namespace to free (MAYBE NULL) + * + * Requires: All references to the namespace must have been put, if the + * namespace was referenced by a profile confining a task, + */ +void aa_free_namespace(struct aa_namespace *ns) +{ + if (!ns) + return; + + aa_policy_destroy(&ns->base); + aa_put_namespace(ns->parent); + + ns->unconfined->ns = NULL; + aa_free_profile(ns->unconfined); + kzfree(ns); +} + +/** + * aa_find_namespace - look up a profile namespace on the namespace list + * @root: namespace to search in (NOT NULL) + * @name: name of namespace to find (NOT NULL) + * + * Returns: a refcounted namespace on the list, or NULL if no namespace + * called @name exists. + * + * refcount released by caller + */ +struct aa_namespace *aa_find_namespace(struct aa_namespace *root, + const char *name) +{ + struct aa_namespace *ns = NULL; + + rcu_read_lock(); + ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); + rcu_read_unlock(); + + return ns; +} + +/** + * aa_prepare_namespace - find an existing or create a new namespace of @name + * @name: the namespace to find or add (MAYBE NULL) + * + * Returns: refcounted namespace or NULL if failed to create one + */ +struct aa_namespace *aa_prepare_namespace(const char *name) +{ + struct aa_namespace *ns, *root; + + root = aa_current_profile()->ns; + + mutex_lock(&root->lock); + + /* if name isn't specified the profile is loaded to the current ns */ + if (!name) { + /* released by caller */ + ns = aa_get_namespace(root); + goto out; + } + + /* try and find the specified ns and if it doesn't exist create it */ + /* released by caller */ + ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); + if (!ns) { + ns = alloc_namespace(root->base.hname, name); + if (!ns) + goto out; + if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) { + AA_ERROR("Failed to create interface for ns %s\n", + ns->base.name); + aa_free_namespace(ns); + ns = NULL; + goto out; + } + ns->parent = aa_get_namespace(root); + list_add_rcu(&ns->base.list, &root->sub_ns); + /* add list ref */ + aa_get_namespace(ns); + } +out: + mutex_unlock(&root->lock); + + /* return ref */ + return ns; +} + +static void __ns_list_release(struct list_head *head); + +/** + * destroy_namespace - remove everything contained by @ns + * @ns: namespace to have it contents removed (NOT NULL) + */ +static void destroy_namespace(struct aa_namespace *ns) +{ + if (!ns) + return; + + mutex_lock(&ns->lock); + /* release all profiles in this namespace */ + __aa_profile_list_release(&ns->base.profiles); + + /* release all sub namespaces */ + __ns_list_release(&ns->sub_ns); + + if (ns->parent) + __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); + __aa_fs_namespace_rmdir(ns); + mutex_unlock(&ns->lock); +} + +/** + * __aa_remove_namespace - remove a namespace and all its children + * @ns: namespace to be removed (NOT NULL) + * + * Requires: ns->parent->lock be held and ns removed from parent. + */ +void __aa_remove_namespace(struct aa_namespace *ns) +{ + /* remove ns from namespace list */ + list_del_rcu(&ns->base.list); + destroy_namespace(ns); + aa_put_namespace(ns); +} + +/** + * __ns_list_release - remove all profile namespaces on the list put refs + * @head: list of profile namespaces (NOT NULL) + * + * Requires: namespace lock be held + */ +static void __ns_list_release(struct list_head *head) +{ + struct aa_namespace *ns, *tmp; + + list_for_each_entry_safe(ns, tmp, head, base.list) + __aa_remove_namespace(ns); + +} + +/** + * aa_alloc_root_ns - allocate the root profile namespace + * + * Returns: %0 on success else error + * + */ +int __init aa_alloc_root_ns(void) +{ + /* released by aa_free_root_ns - used as list ref*/ + root_ns = alloc_namespace(NULL, "root"); + if (!root_ns) + return -ENOMEM; + + return 0; +} + + /** + * aa_free_root_ns - free the root profile namespace + */ +void __init aa_free_root_ns(void) +{ + struct aa_namespace *ns = root_ns; + + root_ns = NULL; + + destroy_namespace(ns); + aa_put_namespace(ns); +} diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index b125acc9aa26..bb2600d9d826 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -15,6 +15,7 @@ #include "include/apparmor.h" #include "include/context.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/domain.h" #include "include/procattr.h" From 98849dff90e270af3b34889b9e08252544f40b5b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:16 -0800 Subject: [PATCH 0379/1587] apparmor: rename namespace to ns to improve code line lengths Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 49 ++++++++------- security/apparmor/domain.c | 24 ++++---- security/apparmor/include/apparmorfs.h | 8 +-- security/apparmor/include/policy.h | 8 +-- security/apparmor/include/policy_ns.h | 43 +++++++------- security/apparmor/policy.c | 32 +++++----- security/apparmor/policy_ns.c | 82 +++++++++++++------------- security/apparmor/procattr.c | 4 +- 8 files changed, 122 insertions(+), 128 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index efac1a9565e2..4409b63f0dd7 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -478,9 +478,9 @@ fail2: return error; } -void __aa_fs_namespace_rmdir(struct aa_namespace *ns) +void __aa_fs_ns_rmdir(struct aa_ns *ns) { - struct aa_namespace *sub; + struct aa_ns *sub; struct aa_profile *child; int i; @@ -492,7 +492,7 @@ void __aa_fs_namespace_rmdir(struct aa_namespace *ns) list_for_each_entry(sub, &ns->sub_ns, base.list) { mutex_lock(&sub->lock); - __aa_fs_namespace_rmdir(sub); + __aa_fs_ns_rmdir(sub); mutex_unlock(&sub->lock); } @@ -502,10 +502,9 @@ void __aa_fs_namespace_rmdir(struct aa_namespace *ns) } } -int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent, - const char *name) +int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name) { - struct aa_namespace *sub; + struct aa_ns *sub; struct aa_profile *child; struct dentry *dent, *dir; int error; @@ -536,7 +535,7 @@ int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent, list_for_each_entry(sub, &ns->sub_ns, base.list) { mutex_lock(&sub->lock); - error = __aa_fs_namespace_mkdir(sub, ns_subns_dir(ns), NULL); + error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL); mutex_unlock(&sub->lock); if (error) goto fail2; @@ -548,7 +547,7 @@ fail: error = PTR_ERR(dent); fail2: - __aa_fs_namespace_rmdir(ns); + __aa_fs_ns_rmdir(ns); return error; } @@ -557,7 +556,7 @@ fail2: #define list_entry_is_head(pos, head, member) (&pos->member == (head)) /** - * __next_namespace - find the next namespace to list + * __next_ns - find the next namespace to list * @root: root namespace to stop search at (NOT NULL) * @ns: current ns position (NOT NULL) * @@ -568,10 +567,9 @@ fail2: * Requires: ns->parent->lock to be held * NOTE: will not unlock root->lock */ -static struct aa_namespace *__next_namespace(struct aa_namespace *root, - struct aa_namespace *ns) +static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns) { - struct aa_namespace *parent, *next; + struct aa_ns *parent, *next; /* is next namespace a child */ if (!list_empty(&ns->sub_ns)) { @@ -604,10 +602,10 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root, * Returns: unrefcounted profile or NULL if no profile * Requires: profile->ns.lock to be held */ -static struct aa_profile *__first_profile(struct aa_namespace *root, - struct aa_namespace *ns) +static struct aa_profile *__first_profile(struct aa_ns *root, + struct aa_ns *ns) { - for (; ns; ns = __next_namespace(root, ns)) { + for (; ns; ns = __next_ns(root, ns)) { if (!list_empty(&ns->base.profiles)) return list_first_entry(&ns->base.profiles, struct aa_profile, base.list); @@ -627,7 +625,7 @@ static struct aa_profile *__first_profile(struct aa_namespace *root, static struct aa_profile *__next_profile(struct aa_profile *p) { struct aa_profile *parent; - struct aa_namespace *ns = p->ns; + struct aa_ns *ns = p->ns; /* is next profile a child */ if (!list_empty(&p->base.profiles)) @@ -661,7 +659,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p) * * Returns: next profile or NULL if there isn't one */ -static struct aa_profile *next_profile(struct aa_namespace *root, +static struct aa_profile *next_profile(struct aa_ns *root, struct aa_profile *profile) { struct aa_profile *next = __next_profile(profile); @@ -669,7 +667,7 @@ static struct aa_profile *next_profile(struct aa_namespace *root, return next; /* finished all profiles in namespace move to next namespace */ - return __first_profile(root, __next_namespace(root, profile->ns)); + return __first_profile(root, __next_ns(root, profile->ns)); } /** @@ -684,9 +682,9 @@ static struct aa_profile *next_profile(struct aa_namespace *root, static void *p_start(struct seq_file *f, loff_t *pos) { struct aa_profile *profile = NULL; - struct aa_namespace *root = aa_current_profile()->ns; + struct aa_ns *root = aa_current_profile()->ns; loff_t l = *pos; - f->private = aa_get_namespace(root); + f->private = aa_get_ns(root); /* find the first profile */ @@ -713,7 +711,7 @@ static void *p_start(struct seq_file *f, loff_t *pos) static void *p_next(struct seq_file *f, void *p, loff_t *pos) { struct aa_profile *profile = p; - struct aa_namespace *ns = f->private; + struct aa_ns *ns = f->private; (*pos)++; return next_profile(ns, profile); @@ -729,14 +727,14 @@ static void *p_next(struct seq_file *f, void *p, loff_t *pos) static void p_stop(struct seq_file *f, void *p) { struct aa_profile *profile = p; - struct aa_namespace *root = f->private, *ns; + struct aa_ns *root = f->private, *ns; if (profile) { for (ns = profile->ns; ns && ns != root; ns = ns->parent) mutex_unlock(&ns->lock); } mutex_unlock(&root->lock); - aa_put_namespace(root); + aa_put_ns(root); } /** @@ -749,7 +747,7 @@ static void p_stop(struct seq_file *f, void *p) static int seq_show_profile(struct seq_file *f, void *p) { struct aa_profile *profile = (struct aa_profile *)p; - struct aa_namespace *root = f->private; + struct aa_ns *root = f->private; if (profile->ns != root) seq_printf(f, ":%s://", aa_ns_name(root, profile->ns)); @@ -951,8 +949,7 @@ static int __init aa_create_aafs(void) if (error) goto error; - error = __aa_fs_namespace_mkdir(root_ns, aa_fs_entry.dentry, - "policy"); + error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy"); if (error) goto error; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 02d2f01e908d..503cb2c54447 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -94,7 +94,7 @@ out: * Returns: permission set */ static struct file_perms change_profile_perms(struct aa_profile *profile, - struct aa_namespace *ns, + struct aa_ns *ns, const char *name, u32 request, unsigned int start) { @@ -171,7 +171,7 @@ static struct aa_profile *__attach_match(const char *name, * * Returns: profile or NULL if no match found */ -static struct aa_profile *find_attach(struct aa_namespace *ns, +static struct aa_profile *find_attach(struct aa_ns *ns, struct list_head *list, const char *name) { struct aa_profile *profile; @@ -240,7 +240,7 @@ static const char *next_name(int xtype, const char *name) static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) { struct aa_profile *new_profile = NULL; - struct aa_namespace *ns = profile->ns; + struct aa_ns *ns = profile->ns; u32 xtype = xindex & AA_X_TYPE_MASK; int index = xindex & AA_X_INDEX_MASK; const char *name; @@ -248,7 +248,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) /* index is guaranteed to be in range, validated at load time */ for (name = profile->file.trans.table[index]; !new_profile && name; name = next_name(xtype, name)) { - struct aa_namespace *new_ns; + struct aa_ns *new_ns; const char *xname = NULL; new_ns = NULL; @@ -268,7 +268,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) ; } /* released below */ - new_ns = aa_find_namespace(ns, ns_name); + new_ns = aa_find_ns(ns, ns_name); if (!new_ns) continue; } else if (*name == '@') { @@ -281,7 +281,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) /* released by caller */ new_profile = aa_lookup_profile(new_ns ? new_ns : ns, xname); - aa_put_namespace(new_ns); + aa_put_ns(new_ns); } /* released by caller */ @@ -302,7 +302,7 @@ static struct aa_profile *x_to_profile(struct aa_profile *profile, const char *name, u32 xindex) { struct aa_profile *new_profile = NULL; - struct aa_namespace *ns = profile->ns; + struct aa_ns *ns = profile->ns; u32 xtype = xindex & AA_X_TYPE_MASK; switch (xtype) { @@ -339,7 +339,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) { struct aa_task_cxt *cxt; struct aa_profile *profile, *new_profile = NULL; - struct aa_namespace *ns; + struct aa_ns *ns; char *buffer = NULL; unsigned int state; struct file_perms perms = {}; @@ -746,7 +746,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, { const struct cred *cred; struct aa_profile *profile, *target = NULL; - struct aa_namespace *ns = NULL; + struct aa_ns *ns = NULL; struct file_perms perms = {}; const char *name = NULL, *info = NULL; int op, error = 0; @@ -780,7 +780,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, if (ns_name) { /* released below */ - ns = aa_find_namespace(profile->ns, ns_name); + ns = aa_find_ns(profile->ns, ns_name); if (!ns) { /* we don't create new namespace in complain mode */ name = ns_name; @@ -790,7 +790,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, } } else /* released below */ - ns = aa_get_namespace(profile->ns); + ns = aa_get_ns(profile->ns); /* if the name was not specified, use the name of the current profile */ if (!hname) { @@ -843,7 +843,7 @@ audit: error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name, hname, GLOBAL_ROOT_UID, info, error); - aa_put_namespace(ns); + aa_put_ns(ns); aa_put_profile(target); put_cred(cred); diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index 414e56878dd0..5626bd48d7cb 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -62,7 +62,7 @@ extern const struct file_operations aa_fs_seq_file_ops; extern void __init aa_destroy_aafs(void); struct aa_profile; -struct aa_namespace; +struct aa_ns; enum aafs_ns_type { AAFS_NS_DIR, @@ -97,8 +97,8 @@ void __aa_fs_profile_rmdir(struct aa_profile *profile); void __aa_fs_profile_migrate_dents(struct aa_profile *old, struct aa_profile *new); int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent); -void __aa_fs_namespace_rmdir(struct aa_namespace *ns); -int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent, - const char *name); +void __aa_fs_ns_rmdir(struct aa_ns *ns); +int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, + const char *name); #endif /* __AA_APPARMORFS_H */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index a1b1d8ab589c..415f8ab0b11e 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -31,7 +31,7 @@ #include "resource.h" -struct aa_namespace; +struct aa_ns; extern const char *const aa_profile_mode_names[]; #define APPARMOR_MODE_NAMES_MAX_INDEX 4 @@ -141,7 +141,7 @@ struct aa_profile { struct rcu_head rcu; struct aa_profile __rcu *parent; - struct aa_namespace *ns; + struct aa_ns *ns; struct aa_replacedby *replacedby; const char *rename; @@ -177,8 +177,8 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); -struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name); -struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name); +struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); +struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); ssize_t aa_remove_profiles(char *name, size_t size); diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 4b9e8c7c669a..323752cc0c87 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -35,7 +35,7 @@ struct aa_ns_acct { int count; }; -/* struct aa_namespace - namespace for a set of profiles +/* struct aa_ns - namespace for a set of profiles * @base: common policy * @parent: parent of namespace * @lock: lock for modifying the object @@ -46,9 +46,9 @@ struct aa_ns_acct { * @uniq_id: a unique id count for the profiles in the namespace * @dents: dentries for the namespaces file entries in apparmorfs * - * An aa_namespace defines the set profiles that are searched to determine + * An aa_ns defines the set profiles that are searched to determine * which profile to attach to a task. Profiles can not be shared between - * aa_namespaces and profile names within a namespace are guaranteed to be + * aa_nss and profile names within a namespace are guaranteed to be * unique. When profiles in separate namespaces have the same name they * are NOT considered to be equivalent. * @@ -57,9 +57,9 @@ struct aa_ns_acct { * * Namespace names must be unique and can not contain the characters :/\0 */ -struct aa_namespace { +struct aa_ns { struct aa_policy base; - struct aa_namespace *parent; + struct aa_ns *parent; struct mutex lock; struct aa_ns_acct acct; struct aa_profile *unconfined; @@ -70,21 +70,20 @@ struct aa_namespace { struct dentry *dents[AAFS_NS_SIZEOF]; }; -extern struct aa_namespace *root_ns; +extern struct aa_ns *root_ns; extern const char *aa_hidden_ns_name; -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view); -const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child); -void aa_free_namespace(struct aa_namespace *ns); +bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view); +const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child); +void aa_free_ns(struct aa_ns *ns); int aa_alloc_root_ns(void); void aa_free_root_ns(void); -void aa_free_namespace_kref(struct kref *kref); +void aa_free_ns_kref(struct kref *kref); -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name); -struct aa_namespace *aa_prepare_namespace(const char *name); -void __aa_remove_namespace(struct aa_namespace *ns); +struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name); +struct aa_ns *aa_prepare_ns(const char *name); +void __aa_remove_ns(struct aa_ns *ns); static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) { @@ -93,13 +92,13 @@ static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) } /** - * aa_get_namespace - increment references count on @ns + * aa_get_ns - increment references count on @ns * @ns: namespace to increment reference count of (MAYBE NULL) * * Returns: pointer to @ns, if @ns is NULL returns NULL * Requires: @ns must be held with valid refcount when called */ -static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) +static inline struct aa_ns *aa_get_ns(struct aa_ns *ns) { if (ns) aa_get_profile(ns->unconfined); @@ -108,19 +107,19 @@ static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) } /** - * aa_put_namespace - decrement refcount on @ns + * aa_put_ns - decrement refcount on @ns * @ns: namespace to put reference of * * Decrement reference count of @ns and if no longer in use free it */ -static inline void aa_put_namespace(struct aa_namespace *ns) +static inline void aa_put_ns(struct aa_ns *ns) { if (ns) aa_put_profile(ns->unconfined); } /** - * __aa_find_namespace - find a namespace on a list by @name + * __aa_find_ns - find a namespace on a list by @name * @head: list to search for namespace on (NOT NULL) * @name: name of namespace to look for (NOT NULL) * @@ -128,10 +127,10 @@ static inline void aa_put_namespace(struct aa_namespace *ns) * * Requires: rcu_read_lock be held */ -static inline struct aa_namespace *__aa_find_namespace(struct list_head *head, - const char *name) +static inline struct aa_ns *__aa_find_ns(struct list_head *head, + const char *name) { - return (struct aa_namespace *)__policy_find(head, name); + return (struct aa_ns *)__policy_find(head, name); } #endif /* AA_NAMESPACE_H */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 2a861824319e..2dd8717a5a89 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -213,7 +213,7 @@ void aa_free_profile(struct aa_profile *profile) aa_policy_destroy(&profile->base); aa_put_profile(rcu_access_pointer(profile->parent)); - aa_put_namespace(profile->ns); + aa_put_ns(profile->ns); kzfree(profile->rename); aa_free_file_rules(&profile->file); @@ -237,7 +237,7 @@ static void aa_free_profile_rcu(struct rcu_head *head) { struct aa_profile *p = container_of(head, struct aa_profile, rcu); if (p->flags & PFLAG_NS_COUNT) - aa_free_namespace(p->ns); + aa_free_ns(p->ns); else aa_free_profile(p); } @@ -324,7 +324,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) /* released on free_profile */ rcu_assign_pointer(profile->parent, aa_get_profile(parent)); - profile->ns = aa_get_namespace(parent->ns); + profile->ns = aa_get_ns(parent->ns); mutex_lock(&profile->ns->lock); __list_add_profile(&parent->base.profiles, profile); @@ -403,7 +403,7 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name) * * Returns: unrefcounted policy or NULL if not found */ -static struct aa_policy *__lookup_parent(struct aa_namespace *ns, +static struct aa_policy *__lookup_parent(struct aa_ns *ns, const char *hname) { struct aa_policy *policy; @@ -466,7 +466,7 @@ static struct aa_profile *__lookup_profile(struct aa_policy *base, * * Returns: refcounted profile or NULL if not found */ -struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname) +struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) { struct aa_profile *profile; @@ -670,7 +670,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, * * Returns: profile to replace (no ref) on success else ptr error */ -static int __lookup_replace(struct aa_namespace *ns, const char *hname, +static int __lookup_replace(struct aa_ns *ns, const char *hname, bool noreplace, struct aa_profile **p, const char **info) { @@ -701,7 +701,7 @@ static int __lookup_replace(struct aa_namespace *ns, const char *hname, ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) { const char *ns_name, *info = NULL; - struct aa_namespace *ns = NULL; + struct aa_ns *ns = NULL; struct aa_load_ent *ent, *tmp; int op = OP_PROF_REPL; ssize_t error; @@ -713,7 +713,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) goto out; /* released below */ - ns = aa_prepare_namespace(ns_name); + ns = aa_prepare_ns(ns_name); if (!ns) { error = audit_policy(op, GFP_KERNEL, ns_name, "failed to prepare namespace", -ENOMEM); @@ -738,7 +738,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) } /* released when @new is freed */ - ent->new->ns = aa_get_namespace(ns); + ent->new->ns = aa_get_ns(ns); if (ent->old || ent->rename) continue; @@ -835,7 +835,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) mutex_unlock(&ns->lock); out: - aa_put_namespace(ns); + aa_put_ns(ns); if (error) return error; @@ -881,7 +881,7 @@ free: */ ssize_t aa_remove_profiles(char *fqname, size_t size) { - struct aa_namespace *root, *ns = NULL; + struct aa_ns *root, *ns = NULL; struct aa_profile *profile = NULL; const char *name = fqname, *info = NULL; ssize_t error = 0; @@ -898,7 +898,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) char *ns_name; name = aa_split_fqname(fqname, &ns_name); /* released below */ - ns = aa_find_namespace(root, ns_name); + ns = aa_find_ns(root, ns_name); if (!ns) { info = "namespace does not exist"; error = -ENOENT; @@ -906,12 +906,12 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) } } else /* released below */ - ns = aa_get_namespace(root); + ns = aa_get_ns(root); if (!name) { /* remove namespace - can only happen if fqname[0] == ':' */ mutex_lock(&ns->parent->lock); - __aa_remove_namespace(ns); + __aa_remove_ns(ns); mutex_unlock(&ns->parent->lock); } else { /* remove profile */ @@ -929,13 +929,13 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) /* don't fail removal if audit fails */ (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); - aa_put_namespace(ns); + aa_put_ns(ns); aa_put_profile(profile); return size; fail_ns_lock: mutex_unlock(&ns->lock); - aa_put_namespace(ns); + aa_put_ns(ns); fail: (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index d4e9924a276e..88b3b3c110e3 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -26,7 +26,7 @@ #include "include/policy.h" /* root profile namespace */ -struct aa_namespace *root_ns; +struct aa_ns *root_ns; const char *aa_hidden_ns_name = "---"; /** @@ -36,7 +36,7 @@ const char *aa_hidden_ns_name = "---"; * * Returns: true if @view is visible from @curr else false */ -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) +bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view) { if (curr == view) return true; @@ -55,7 +55,7 @@ bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) * * Returns: name of @view visible from @curr */ -const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) +const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view) { /* if view == curr then the namespace name isn't displayed */ if (curr == view) @@ -75,16 +75,15 @@ const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) } /** - * alloc_namespace - allocate, initialize and return a new namespace + * alloc_ns - allocate, initialize and return a new namespace * @prefix: parent namespace name (MAYBE NULL) * @name: a preallocated name (NOT NULL) * * Returns: refcounted namespace or NULL on failure. */ -static struct aa_namespace *alloc_namespace(const char *prefix, - const char *name) +static struct aa_ns *alloc_ns(const char *prefix, const char *name) { - struct aa_namespace *ns; + struct aa_ns *ns; ns = kzalloc(sizeof(*ns), GFP_KERNEL); AA_DEBUG("%s(%p)\n", __func__, ns); @@ -96,7 +95,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, INIT_LIST_HEAD(&ns->sub_ns); mutex_init(&ns->lock); - /* released by free_namespace */ + /* released by aa_free_ns() */ ns->unconfined = aa_alloc_profile("unconfined"); if (!ns->unconfined) goto fail_unconfined; @@ -120,19 +119,19 @@ fail_ns: } /** - * aa_free_namespace - free a profile namespace + * aa_free_ns - free a profile namespace * @ns: the namespace to free (MAYBE NULL) * * Requires: All references to the namespace must have been put, if the * namespace was referenced by a profile confining a task, */ -void aa_free_namespace(struct aa_namespace *ns) +void aa_free_ns(struct aa_ns *ns) { if (!ns) return; aa_policy_destroy(&ns->base); - aa_put_namespace(ns->parent); + aa_put_ns(ns->parent); ns->unconfined->ns = NULL; aa_free_profile(ns->unconfined); @@ -140,7 +139,7 @@ void aa_free_namespace(struct aa_namespace *ns) } /** - * aa_find_namespace - look up a profile namespace on the namespace list + * aa_find_ns - look up a profile namespace on the namespace list * @root: namespace to search in (NOT NULL) * @name: name of namespace to find (NOT NULL) * @@ -149,27 +148,26 @@ void aa_free_namespace(struct aa_namespace *ns) * * refcount released by caller */ -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name) +struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) { - struct aa_namespace *ns = NULL; + struct aa_ns *ns = NULL; rcu_read_lock(); - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); + ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name)); rcu_read_unlock(); return ns; } /** - * aa_prepare_namespace - find an existing or create a new namespace of @name + * aa_prepare_ns - find an existing or create a new namespace of @name * @name: the namespace to find or add (MAYBE NULL) * - * Returns: refcounted namespace or NULL if failed to create one + * Returns: refcounted ns or NULL if failed to create one */ -struct aa_namespace *aa_prepare_namespace(const char *name) +struct aa_ns *aa_prepare_ns(const char *name) { - struct aa_namespace *ns, *root; + struct aa_ns *ns, *root; root = aa_current_profile()->ns; @@ -178,28 +176,28 @@ struct aa_namespace *aa_prepare_namespace(const char *name) /* if name isn't specified the profile is loaded to the current ns */ if (!name) { /* released by caller */ - ns = aa_get_namespace(root); + ns = aa_get_ns(root); goto out; } /* try and find the specified ns and if it doesn't exist create it */ /* released by caller */ - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); + ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name)); if (!ns) { - ns = alloc_namespace(root->base.hname, name); + ns = alloc_ns(root->base.hname, name); if (!ns) goto out; - if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) { + if (__aa_fs_ns_mkdir(ns, ns_subns_dir(root), name)) { AA_ERROR("Failed to create interface for ns %s\n", ns->base.name); - aa_free_namespace(ns); + aa_free_ns(ns); ns = NULL; goto out; } - ns->parent = aa_get_namespace(root); + ns->parent = aa_get_ns(root); list_add_rcu(&ns->base.list, &root->sub_ns); /* add list ref */ - aa_get_namespace(ns); + aa_get_ns(ns); } out: mutex_unlock(&root->lock); @@ -211,10 +209,10 @@ out: static void __ns_list_release(struct list_head *head); /** - * destroy_namespace - remove everything contained by @ns - * @ns: namespace to have it contents removed (NOT NULL) + * destroy_ns - remove everything contained by @ns + * @ns: ns to have it contents removed (NOT NULL) */ -static void destroy_namespace(struct aa_namespace *ns) +static void destroy_ns(struct aa_ns *ns) { if (!ns) return; @@ -228,22 +226,22 @@ static void destroy_namespace(struct aa_namespace *ns) if (ns->parent) __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); - __aa_fs_namespace_rmdir(ns); + __aa_fs_ns_rmdir(ns); mutex_unlock(&ns->lock); } /** - * __aa_remove_namespace - remove a namespace and all its children + * __aa_remove_ns - remove a namespace and all its children * @ns: namespace to be removed (NOT NULL) * * Requires: ns->parent->lock be held and ns removed from parent. */ -void __aa_remove_namespace(struct aa_namespace *ns) +void __aa_remove_ns(struct aa_ns *ns) { /* remove ns from namespace list */ list_del_rcu(&ns->base.list); - destroy_namespace(ns); - aa_put_namespace(ns); + destroy_ns(ns); + aa_put_ns(ns); } /** @@ -254,15 +252,15 @@ void __aa_remove_namespace(struct aa_namespace *ns) */ static void __ns_list_release(struct list_head *head) { - struct aa_namespace *ns, *tmp; + struct aa_ns *ns, *tmp; list_for_each_entry_safe(ns, tmp, head, base.list) - __aa_remove_namespace(ns); + __aa_remove_ns(ns); } /** - * aa_alloc_root_ns - allocate the root profile namespace + * aa_alloc_root_ns - allocate the root profile namespcae * * Returns: %0 on success else error * @@ -270,7 +268,7 @@ static void __ns_list_release(struct list_head *head) int __init aa_alloc_root_ns(void) { /* released by aa_free_root_ns - used as list ref*/ - root_ns = alloc_namespace(NULL, "root"); + root_ns = alloc_ns(NULL, "root"); if (!root_ns) return -ENOMEM; @@ -282,10 +280,10 @@ int __init aa_alloc_root_ns(void) */ void __init aa_free_root_ns(void) { - struct aa_namespace *ns = root_ns; + struct aa_ns *ns = root_ns; root_ns = NULL; - destroy_namespace(ns); - aa_put_namespace(ns); + destroy_ns(ns); + aa_put_ns(ns); } diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index bb2600d9d826..15ddf74ac269 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -40,8 +40,8 @@ int aa_getprocattr(struct aa_profile *profile, char **string) int len = 0, mode_len = 0, ns_len = 0, name_len; const char *mode_str = aa_profile_mode_names[profile->mode]; const char *ns_name = NULL; - struct aa_namespace *ns = profile->ns; - struct aa_namespace *current_ns = __aa_current_profile()->ns; + struct aa_ns *ns = profile->ns; + struct aa_ns *current_ns = __aa_current_profile()->ns; char *s; if (!aa_ns_visible(current_ns, ns)) From 121d4a91e3c12ddfb167edafb9aa64cc5cc3a406 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:17 -0800 Subject: [PATCH 0380/1587] apparmor: rename sid to secid Move to common terminology with other LSMs and kernel infrastucture Signed-off-by: John Johansen --- security/apparmor/Makefile | 2 +- security/apparmor/include/{sid.h => secid.h} | 18 +++---- security/apparmor/secid.c | 55 ++++++++++++++++++++ security/apparmor/sid.c | 55 -------------------- 4 files changed, 65 insertions(+), 65 deletions(-) rename security/apparmor/include/{sid.h => secid.h} (50%) create mode 100644 security/apparmor/secid.c delete mode 100644 security/apparmor/sid.c diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index 3485f49d9de9..ad369a7aac24 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ - resource.o sid.o file.o policy_ns.o + resource.o secid.o file.o policy_ns.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o clean-files := capability_names.h rlim_names.h diff --git a/security/apparmor/include/sid.h b/security/apparmor/include/secid.h similarity index 50% rename from security/apparmor/include/sid.h rename to security/apparmor/include/secid.h index 513ca0e48965..95ed86a0f1e2 100644 --- a/security/apparmor/include/sid.h +++ b/security/apparmor/include/secid.h @@ -1,7 +1,7 @@ /* * AppArmor security module * - * This file contains AppArmor security identifier (sid) definitions + * This file contains AppArmor security identifier (secid) definitions * * Copyright 2009-2010 Canonical Ltd. * @@ -11,16 +11,16 @@ * License. */ -#ifndef __AA_SID_H -#define __AA_SID_H +#ifndef __AA_SECID_H +#define __AA_SECID_H #include -/* sid value that will not be allocated */ -#define AA_SID_INVALID 0 -#define AA_SID_ALLOC AA_SID_INVALID +/* secid value that will not be allocated */ +#define AA_SECID_INVALID 0 +#define AA_SECID_ALLOC AA_SECID_INVALID -u32 aa_alloc_sid(void); -void aa_free_sid(u32 sid); +u32 aa_alloc_secid(void); +void aa_free_secid(u32 secid); -#endif /* __AA_SID_H */ +#endif /* __AA_SECID_H */ diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c new file mode 100644 index 000000000000..3a3edbad0b21 --- /dev/null +++ b/security/apparmor/secid.c @@ -0,0 +1,55 @@ +/* + * AppArmor security module + * + * This file contains AppArmor security identifier (secid) manipulation fns + * + * Copyright 2009-2010 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * + * AppArmor allocates a unique secid for every profile loaded. If a profile + * is replaced it receives the secid of the profile it is replacing. + * + * The secid value of 0 is invalid. + */ + +#include +#include +#include + +#include "include/secid.h" + +/* global counter from which secids are allocated */ +static u32 global_secid; +static DEFINE_SPINLOCK(secid_lock); + +/* TODO FIXME: add secid to profile mapping, and secid recycling */ + +/** + * aa_alloc_secid - allocate a new secid for a profile + */ +u32 aa_alloc_secid(void) +{ + u32 secid; + + /* + * TODO FIXME: secid recycling - part of profile mapping table + */ + spin_lock(&secid_lock); + secid = (++global_secid); + spin_unlock(&secid_lock); + return secid; +} + +/** + * aa_free_secid - free a secid + * @secid: secid to free + */ +void aa_free_secid(u32 secid) +{ + ; /* NOP ATM */ +} diff --git a/security/apparmor/sid.c b/security/apparmor/sid.c deleted file mode 100644 index f0b34f76ebef..000000000000 --- a/security/apparmor/sid.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * AppArmor security module - * - * This file contains AppArmor security identifier (sid) manipulation fns - * - * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * - * AppArmor allocates a unique sid for every profile loaded. If a profile - * is replaced it receives the sid of the profile it is replacing. - * - * The sid value of 0 is invalid. - */ - -#include -#include -#include - -#include "include/sid.h" - -/* global counter from which sids are allocated */ -static u32 global_sid; -static DEFINE_SPINLOCK(sid_lock); - -/* TODO FIXME: add sid to profile mapping, and sid recycling */ - -/** - * aa_alloc_sid - allocate a new sid for a profile - */ -u32 aa_alloc_sid(void) -{ - u32 sid; - - /* - * TODO FIXME: sid recycling - part of profile mapping table - */ - spin_lock(&sid_lock); - sid = (++global_sid); - spin_unlock(&sid_lock); - return sid; -} - -/** - * aa_free_sid - free a sid - * @sid: sid to free - */ -void aa_free_sid(u32 sid) -{ - ; /* NOP ATM */ -} From d97d51d253e08e059bba40002407ec3d188feafb Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:18 -0800 Subject: [PATCH 0381/1587] apparmor: rename PFLAG_INVALID to PFLAG_STALE Invalid does not convey the meaning of the flag anymore so rename it. Signed-off-by: John Johansen --- security/apparmor/include/context.h | 2 +- security/apparmor/include/policy.h | 6 +++--- security/apparmor/policy.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 6bf65798e5d1..a0acc2390fae 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -152,7 +152,7 @@ static inline struct aa_profile *aa_current_profile(void) struct aa_profile *profile; BUG_ON(!cxt || !cxt->profile); - if (PROFILE_INVALID(cxt->profile)) { + if (profile_is_stale(cxt->profile)) { profile = aa_get_newest_profile(cxt->profile); aa_replace_current_profile(profile); aa_put_profile(profile); diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 415f8ab0b11e..56bef768c7eb 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -46,7 +46,7 @@ extern const char *const aa_profile_mode_names[]; #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) -#define PROFILE_INVALID(_profile) ((_profile)->flags & PFLAG_INVALID) +#define profile_is_stale(_profile) ((_profile)->flags & PFLAG_STALE) #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) @@ -71,7 +71,7 @@ enum profile_flags { PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */ PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */ PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */ - PFLAG_INVALID = 0x200, /* profile replaced/removed */ + PFLAG_STALE = 0x200, /* profile replaced/removed */ PFLAG_NS_COUNT = 0x400, /* carries NS ref count */ /* These flags must correspond with PATH_flags */ @@ -253,7 +253,7 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) if (!p) return NULL; - if (PROFILE_INVALID(p)) + if (profile_is_stale(p)) return aa_get_profile_rcu(&p->replacedby->profile); return aa_get_profile(p); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 2dd8717a5a89..edc81a0d0cb4 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -106,7 +106,7 @@ void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new) tmp = rcu_dereference_protected(orig->replacedby->profile, mutex_is_locked(&orig->ns->lock)); rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); - orig->flags |= PFLAG_INVALID; + orig->flags |= PFLAG_STALE; aa_put_profile(tmp); } From 8399588a7f9def9195e577f988ad06f2a0ffb1af Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:19 -0800 Subject: [PATCH 0382/1587] apparmor: rename replacedby to proxy Proxy is shorter and a better fit than replaceby, so rename it. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 36 +++++++-------- security/apparmor/context.c | 2 +- security/apparmor/include/policy.h | 20 ++++----- security/apparmor/policy.c | 70 +++++++++++++++--------------- security/apparmor/policy_ns.c | 2 +- 5 files changed, 65 insertions(+), 65 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 4409b63f0dd7..0f1a4a28e025 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -228,12 +228,12 @@ const struct file_operations aa_fs_seq_file_ops = { static int aa_fs_seq_profile_open(struct inode *inode, struct file *file, int (*show)(struct seq_file *, void *)) { - struct aa_replacedby *r = aa_get_replacedby(inode->i_private); - int error = single_open(file, show, r); + struct aa_proxy *proxy = aa_get_proxy(inode->i_private); + int error = single_open(file, show, proxy); if (error) { file->private_data = NULL; - aa_put_replacedby(r); + aa_put_proxy(proxy); } return error; @@ -243,14 +243,14 @@ static int aa_fs_seq_profile_release(struct inode *inode, struct file *file) { struct seq_file *seq = (struct seq_file *) file->private_data; if (seq) - aa_put_replacedby(seq->private); + aa_put_proxy(seq->private); return single_release(inode, file); } static int aa_fs_seq_profname_show(struct seq_file *seq, void *v) { - struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); seq_printf(seq, "%s\n", profile->base.name); aa_put_profile(profile); @@ -272,8 +272,8 @@ static const struct file_operations aa_fs_profname_fops = { static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v) { - struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]); aa_put_profile(profile); @@ -295,8 +295,8 @@ static const struct file_operations aa_fs_profmode_fops = { static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v) { - struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); if (profile->attach) seq_printf(seq, "%s\n", profile->attach); else if (profile->xmatch) @@ -323,8 +323,8 @@ static const struct file_operations aa_fs_profattach_fops = { static int aa_fs_seq_hash_show(struct seq_file *seq, void *v) { - struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); unsigned int i, size = aa_hash_size(); if (profile->hash) { @@ -363,13 +363,13 @@ void __aa_fs_profile_rmdir(struct aa_profile *profile) __aa_fs_profile_rmdir(child); for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) { - struct aa_replacedby *r; + struct aa_proxy *proxy; if (!profile->dents[i]) continue; - r = d_inode(profile->dents[i])->i_private; + proxy = d_inode(profile->dents[i])->i_private; securityfs_remove(profile->dents[i]); - aa_put_replacedby(r); + aa_put_proxy(proxy); profile->dents[i] = NULL; } } @@ -391,12 +391,12 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name, struct aa_profile *profile, const struct file_operations *fops) { - struct aa_replacedby *r = aa_get_replacedby(profile->replacedby); + struct aa_proxy *proxy = aa_get_proxy(profile->proxy); struct dentry *dent; - dent = securityfs_create_file(name, S_IFREG | 0444, dir, r, fops); + dent = securityfs_create_file(name, S_IFREG | 0444, dir, proxy, fops); if (IS_ERR(dent)) - aa_put_replacedby(r); + aa_put_proxy(proxy); return dent; } diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 3064c6ced87c..3c4f534ef88c 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -112,7 +112,7 @@ int aa_replace_current_profile(struct aa_profile *profile) aa_clear_task_cxt_trans(cxt); /* be careful switching cxt->profile, when racing replacement it - * is possible that cxt->profile->replacedby->profile is the reference + * is possible that cxt->profile->proxy->profile is the reference * keeping @profile valid, so make sure to get its reference before * dropping the reference on cxt->profile */ aa_get_profile(profile); diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 56bef768c7eb..f55ecb8b3777 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -91,7 +91,7 @@ struct aa_policydb { }; -struct aa_replacedby { +struct aa_proxy { struct kref count; struct aa_profile __rcu *profile; }; @@ -103,7 +103,7 @@ struct aa_replacedby { * @rcu: rcu head used when removing from @list * @parent: parent of profile * @ns: namespace the profile is in - * @replacedby: is set to the profile that replaced this profile + * @proxy: is set to the profile that replaced this profile * @rename: optional profile name that this profile renamed * @attach: human readable attachment string * @xmatch: optional extended matching for unconfined executables names @@ -126,7 +126,7 @@ struct aa_replacedby { * used to determine profile attachment against unconfined tasks. All other * attachments are determined by profile X transition rules. * - * The @replacedby struct is write protected by the profile lock. + * The @proxy struct is write protected by the profile lock. * * Profiles have a hierarchy where hats and children profiles keep * a reference to their parent. @@ -142,7 +142,7 @@ struct aa_profile { struct aa_profile __rcu *parent; struct aa_ns *ns; - struct aa_replacedby *replacedby; + struct aa_proxy *proxy; const char *rename; const char *attach; @@ -166,12 +166,12 @@ struct aa_profile { extern enum profile_mode aa_g_profile_mode; -void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new); +void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new); void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); -void aa_free_replacedby_kref(struct kref *kref); +void aa_free_proxy_kref(struct kref *kref); struct aa_profile *aa_alloc_profile(const char *name); struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); @@ -254,7 +254,7 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) return NULL; if (profile_is_stale(p)) - return aa_get_profile_rcu(&p->replacedby->profile); + return aa_get_profile_rcu(&p->proxy->profile); return aa_get_profile(p); } @@ -269,7 +269,7 @@ static inline void aa_put_profile(struct aa_profile *p) kref_put(&p->count, aa_free_profile_kref); } -static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p) +static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *p) { if (p) kref_get(&(p->count)); @@ -277,10 +277,10 @@ static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p) return p; } -static inline void aa_put_replacedby(struct aa_replacedby *p) +static inline void aa_put_proxy(struct aa_proxy *p) { if (p) - kref_put(&p->count, aa_free_replacedby_kref); + kref_put(&p->count, aa_free_proxy_kref); } static inline int AUDIT_MODE(struct aa_profile *profile) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index edc81a0d0cb4..a4bf6756bc1c 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -99,13 +99,13 @@ const char *const aa_profile_mode_names[] = { /* requires profile list write lock held */ -void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new) +void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new) { struct aa_profile *tmp; - tmp = rcu_dereference_protected(orig->replacedby->profile, + tmp = rcu_dereference_protected(orig->proxy->profile, mutex_is_locked(&orig->ns->lock)); - rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); + rcu_assign_pointer(orig->proxy->profile, aa_get_profile(new)); orig->flags |= PFLAG_STALE; aa_put_profile(tmp); } @@ -156,7 +156,7 @@ static void __remove_profile(struct aa_profile *profile) /* release any children lists first */ __aa_profile_list_release(&profile->base.profiles); /* released by free_profile */ - __aa_update_replacedby(profile, profile->ns->unconfined); + __aa_update_proxy(profile, profile->ns->unconfined); __aa_fs_profile_rmdir(profile); __list_remove_profile(profile); } @@ -175,21 +175,21 @@ void __aa_profile_list_release(struct list_head *head) } -static void free_replacedby(struct aa_replacedby *r) +static void free_proxy(struct aa_proxy *p) { - if (r) { + if (p) { /* r->profile will not be updated any more as r is dead */ - aa_put_profile(rcu_dereference_protected(r->profile, true)); - kzfree(r); + aa_put_profile(rcu_dereference_protected(p->profile, true)); + kzfree(p); } } -void aa_free_replacedby_kref(struct kref *kref) +void aa_free_proxy_kref(struct kref *kref) { - struct aa_replacedby *r = container_of(kref, struct aa_replacedby, - count); - free_replacedby(r); + struct aa_proxy *p = container_of(kref, struct aa_proxy, count); + + free_proxy(p); } /** @@ -223,7 +223,7 @@ void aa_free_profile(struct aa_profile *profile) kzfree(profile->dirname); aa_put_dfa(profile->xmatch); aa_put_dfa(profile->policy.dfa); - aa_put_replacedby(profile->replacedby); + aa_put_proxy(profile->proxy); kzfree(profile->hash); kzfree(profile); @@ -267,10 +267,10 @@ struct aa_profile *aa_alloc_profile(const char *hname) if (!profile) return NULL; - profile->replacedby = kzalloc(sizeof(struct aa_replacedby), GFP_KERNEL); - if (!profile->replacedby) + profile->proxy = kzalloc(sizeof(struct aa_proxy), GFP_KERNEL); + if (!profile->proxy) goto fail; - kref_init(&profile->replacedby->count); + kref_init(&profile->proxy->count); if (!aa_policy_init(&profile->base, NULL, hname)) goto fail; @@ -280,7 +280,7 @@ struct aa_profile *aa_alloc_profile(const char *hname) return profile; fail: - kzfree(profile->replacedby); + kzfree(profile->proxy); kzfree(profile); return NULL; @@ -598,7 +598,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh, * __replace_profile - replace @old with @new on a list * @old: profile to be replaced (NOT NULL) * @new: profile to replace @old with (NOT NULL) - * @share_replacedby: transfer @old->replacedby to @new + * @share_proxy: transfer @old->proxy to @new * * Will duplicate and refcount elements that @new inherits from @old * and will inherit @old children. @@ -608,7 +608,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh, * Requires: namespace list lock be held, or list not be shared */ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, - bool share_replacedby) + bool share_proxy) { struct aa_profile *child, *tmp; @@ -623,7 +623,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, p = __find_child(&new->base.profiles, child->base.name); if (p) { /* @p replaces @child */ - __replace_profile(child, p, share_replacedby); + __replace_profile(child, p, share_proxy); continue; } @@ -641,13 +641,13 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, struct aa_profile *parent = aa_deref_parent(old); rcu_assign_pointer(new->parent, aa_get_profile(parent)); } - __aa_update_replacedby(old, new); - if (share_replacedby) { - aa_put_replacedby(new->replacedby); - new->replacedby = aa_get_replacedby(old->replacedby); - } else if (!rcu_access_pointer(new->replacedby->profile)) - /* aafs interface uses replacedby */ - rcu_assign_pointer(new->replacedby->profile, + __aa_update_proxy(old, new); + if (share_proxy) { + aa_put_proxy(new->proxy); + new->proxy = aa_get_proxy(old->proxy); + } else if (!rcu_access_pointer(new->proxy->profile)) + /* aafs interface uses proxy */ + rcu_assign_pointer(new->proxy->profile, aa_get_profile(new)); __aa_fs_profile_migrate_dents(old, new); @@ -797,15 +797,15 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) if (ent->old) { __replace_profile(ent->old, ent->new, 1); if (ent->rename) { - /* aafs interface uses replacedby */ - struct aa_replacedby *r = ent->new->replacedby; + /* aafs interface uses proxy */ + struct aa_proxy *r = ent->new->proxy; rcu_assign_pointer(r->profile, aa_get_profile(ent->new)); __replace_profile(ent->rename, ent->new, 0); } } else if (ent->rename) { - /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, + /* aafs interface uses proxy */ + rcu_assign_pointer(ent->new->proxy->profile, aa_get_profile(ent->new)); __replace_profile(ent->rename, ent->new, 0); } else if (ent->new->parent) { @@ -819,14 +819,14 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) rcu_assign_pointer(ent->new->parent, newest); aa_put_profile(parent); } - /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, + /* aafs interface uses proxy */ + rcu_assign_pointer(ent->new->proxy->profile, aa_get_profile(ent->new)); __list_add_profile(&newest->base.profiles, ent->new); aa_put_profile(newest); } else { - /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, + /* aafs interface uses proxy */ + rcu_assign_pointer(ent->new->proxy->profile, aa_get_profile(ent->new)); __list_add_profile(&ns->base.profiles, ent->new); } diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 88b3b3c110e3..71fbd14e3b37 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -225,7 +225,7 @@ static void destroy_ns(struct aa_ns *ns) __ns_list_release(&ns->sub_ns); if (ns->parent) - __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); + __aa_update_proxy(ns->unconfined, ns->parent->unconfined); __aa_fs_ns_rmdir(ns); mutex_unlock(&ns->lock); } From 1741e9eb8c15de0ba6598a342c51d0688cb569d2 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:21 -0800 Subject: [PATCH 0383/1587] apparmor: add strn version of lookup_profile fn Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 2 ++ security/apparmor/policy.c | 36 +++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index f55ecb8b3777..c90f4a2ffe57 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -177,6 +177,8 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); +struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, + size_t n); struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index a4bf6756bc1c..291810490eaf 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -427,9 +427,10 @@ static struct aa_policy *__lookup_parent(struct aa_ns *ns, } /** - * __lookup_profile - lookup the profile matching @hname + * __lookupn_profile - lookup the profile matching @hname * @base: base list to start looking up profile name from (NOT NULL) * @hname: hierarchical profile name (NOT NULL) + * @n: length of @hname * * Requires: rcu_read_lock be held * @@ -437,53 +438,66 @@ static struct aa_policy *__lookup_parent(struct aa_ns *ns, * * Do a relative name lookup, recursing through profile tree. */ -static struct aa_profile *__lookup_profile(struct aa_policy *base, - const char *hname) +static struct aa_profile *__lookupn_profile(struct aa_policy *base, + const char *hname, size_t n) { struct aa_profile *profile = NULL; - char *split; + const char *split; - for (split = strstr(hname, "//"); split;) { + for (split = strnstr(hname, "//", n); split; + split = strnstr(hname, "//", n)) { profile = __strn_find_child(&base->profiles, hname, split - hname); if (!profile) return NULL; base = &profile->base; + n -= split + 2 - hname; hname = split + 2; - split = strstr(hname, "//"); } - profile = __find_child(&base->profiles, hname); + if (n) + return __strn_find_child(&base->profiles, hname, n); + return NULL; +} - return profile; +static struct aa_profile *__lookup_profile(struct aa_policy *base, + const char *hname) +{ + return __lookupn_profile(base, hname, strlen(hname)); } /** * aa_lookup_profile - find a profile by its full or partial name * @ns: the namespace to start from (NOT NULL) * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL) + * @n: size of @hname * * Returns: refcounted profile or NULL if not found */ -struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) +struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, + size_t n) { struct aa_profile *profile; rcu_read_lock(); do { - profile = __lookup_profile(&ns->base, hname); + profile = __lookupn_profile(&ns->base, hname, n); } while (profile && !aa_get_profile_not0(profile)); rcu_read_unlock(); /* the unconfined profile is not in the regular profile list */ - if (!profile && strcmp(hname, "unconfined") == 0) + if (!profile && strncmp(hname, "unconfined", n) == 0) profile = aa_get_newest_profile(ns->unconfined); /* refcount released by caller */ return profile; } +struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) +{ + return aa_lookupn_profile(ns, hname, strlen(hname)); +} /** * replacement_allowed - test to see if replacement is allowed * @profile: profile to test if it can be replaced (MAYBE NULL) From 9a2d40c12d00ead1b1a3ac8383d2d66e35674fdb Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:22 -0800 Subject: [PATCH 0384/1587] apparmor: add strn version of aa_find_ns Signed-off-by: John Johansen --- security/apparmor/include/policy_ns.h | 13 +++++++++--- security/apparmor/policy_ns.c | 30 ++++++++++++++++++++------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 323752cc0c87..381f8b078548 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -82,6 +82,7 @@ void aa_free_root_ns(void); void aa_free_ns_kref(struct kref *kref); struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name); +struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n); struct aa_ns *aa_prepare_ns(const char *name); void __aa_remove_ns(struct aa_ns *ns); @@ -119,18 +120,24 @@ static inline void aa_put_ns(struct aa_ns *ns) } /** - * __aa_find_ns - find a namespace on a list by @name + * __aa_findn_ns - find a namespace on a list by @name * @head: list to search for namespace on (NOT NULL) * @name: name of namespace to look for (NOT NULL) - * + * @n: length of @name * Returns: unrefcounted namespace * * Requires: rcu_read_lock be held */ +static inline struct aa_ns *__aa_findn_ns(struct list_head *head, + const char *name, size_t n) +{ + return (struct aa_ns *)__policy_strn_find(head, name, n); +} + static inline struct aa_ns *__aa_find_ns(struct list_head *head, const char *name) { - return (struct aa_ns *)__policy_find(head, name); + return __aa_findn_ns(head, name, strlen(name)); } #endif /* AA_NAMESPACE_H */ diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 71fbd14e3b37..9746643cbab2 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -138,6 +138,28 @@ void aa_free_ns(struct aa_ns *ns) kzfree(ns); } +/** + * aa_findn_ns - look up a profile namespace on the namespace list + * @root: namespace to search in (NOT NULL) + * @name: name of namespace to find (NOT NULL) + * @n: length of @name + * + * Returns: a refcounted namespace on the list, or NULL if no namespace + * called @name exists. + * + * refcount released by caller + */ +struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n) +{ + struct aa_ns *ns = NULL; + + rcu_read_lock(); + ns = aa_get_ns(__aa_findn_ns(&root->sub_ns, name, n)); + rcu_read_unlock(); + + return ns; +} + /** * aa_find_ns - look up a profile namespace on the namespace list * @root: namespace to search in (NOT NULL) @@ -150,13 +172,7 @@ void aa_free_ns(struct aa_ns *ns) */ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) { - struct aa_ns *ns = NULL; - - rcu_read_lock(); - ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name)); - rcu_read_unlock(); - - return ns; + return aa_findn_ns(root, name, strlen(name)); } /** From 3b0aaf5866bf92a3e47627a02ed5e1be6d7cc110 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:23 -0800 Subject: [PATCH 0385/1587] apparmor: add lib fn to find the "split" for fqnames Signed-off-by: John Johansen --- security/apparmor/include/lib.h | 2 ++ security/apparmor/lib.c | 53 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 74cc68ea4c12..4699c2b43fa0 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -38,6 +38,8 @@ extern int apparmor_initialized __initdata; /* fn's in lib */ char *aa_split_fqname(char *args, char **ns_name); +const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, + size_t *ns_len); void aa_info_message(const char *str); void *__aa_kvmalloc(size_t size, gfp_t flags); diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index e29ccdb0309a..fec78eecce0d 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -12,6 +12,7 @@ * License. */ +#include #include #include #include @@ -60,6 +61,58 @@ char *aa_split_fqname(char *fqname, char **ns_name) return name; } +/** + * skipn_spaces - Removes leading whitespace from @str. + * @str: The string to be stripped. + * + * Returns a pointer to the first non-whitespace character in @str. + * if all whitespace will return NULL + */ + +static const char *skipn_spaces(const char *str, size_t n) +{ + for (; n && isspace(*str); --n) + ++str; + if (n) + return (char *)str; + return NULL; +} + +const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, + size_t *ns_len) +{ + const char *end = fqname + n; + const char *name = skipn_spaces(fqname, n); + + if (!name) + return NULL; + *ns_name = NULL; + *ns_len = 0; + if (name[0] == ':') { + char *split = strnchr(&name[1], end - &name[1], ':'); + *ns_name = skipn_spaces(&name[1], end - &name[1]); + if (!*ns_name) + return NULL; + if (split) { + *ns_len = split - *ns_name; + if (*ns_len == 0) + *ns_name = NULL; + split++; + if (end - split > 1 && strncmp(split, "//", 2) == 0) + split += 2; + name = skipn_spaces(split, end - split); + } else { + /* a ns name without a following profile is allowed */ + name = NULL; + *ns_len = end - *ns_name; + } + } + if (name && *name == 0) + name = NULL; + + return name; +} + /** * aa_info_message - log a none profile related status message * @str: message to log From 31617ddfdd7764a5046f076247208aa324458069 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:24 -0800 Subject: [PATCH 0386/1587] apparmor: add fn to lookup profiles by fqname Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 2 ++ security/apparmor/include/policy_ns.h | 10 ++++----- security/apparmor/policy.c | 29 +++++++++++++++++++++++++++ security/apparmor/policy_ns.c | 4 ++-- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index c90f4a2ffe57..da62d29d3992 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -180,6 +180,8 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, size_t n); struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); +struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, + const char *fqname, size_t n); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 381f8b078548..ebf9b40f84ed 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -46,11 +46,11 @@ struct aa_ns_acct { * @uniq_id: a unique id count for the profiles in the namespace * @dents: dentries for the namespaces file entries in apparmorfs * - * An aa_ns defines the set profiles that are searched to determine - * which profile to attach to a task. Profiles can not be shared between - * aa_nss and profile names within a namespace are guaranteed to be - * unique. When profiles in separate namespaces have the same name they - * are NOT considered to be equivalent. + * An aa_ns defines the set profiles that are searched to determine which + * profile to attach to a task. Profiles can not be shared between aa_ns + * and profile names within a namespace are guaranteed to be unique. When + * profiles in separate namespaces have the same name they are NOT considered + * to be equivalent. * * Namespaces are hierarchical and only namespaces and profiles below the * current namespace are visible. diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 291810490eaf..7fde5785005d 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -498,6 +498,35 @@ struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) { return aa_lookupn_profile(ns, hname, strlen(hname)); } + +struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, + const char *fqname, size_t n) +{ + struct aa_profile *profile; + struct aa_ns *ns; + const char *name, *ns_name; + size_t ns_len; + + name = aa_splitn_fqname(fqname, n, &ns_name, &ns_len); + if (ns_name) { + ns = aa_findn_ns(base->ns, ns_name, ns_len); + if (!ns) + return NULL; + } else + ns = aa_get_ns(base->ns); + + if (name) + profile = aa_lookupn_profile(ns, name, n - (name - fqname)); + else if (ns) + /* default profile for ns, currently unconfined */ + profile = aa_get_newest_profile(ns->unconfined); + else + profile = NULL; + aa_put_ns(ns); + + return profile; +} + /** * replacement_allowed - test to see if replacement is allowed * @profile: profile to test if it can be replaced (MAYBE NULL) diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 9746643cbab2..bab23cce197c 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -226,7 +226,7 @@ static void __ns_list_release(struct list_head *head); /** * destroy_ns - remove everything contained by @ns - * @ns: ns to have it contents removed (NOT NULL) + * @ns: namespace to have it contents removed (NOT NULL) */ static void destroy_ns(struct aa_ns *ns) { @@ -276,7 +276,7 @@ static void __ns_list_release(struct list_head *head) } /** - * aa_alloc_root_ns - allocate the root profile namespcae + * aa_alloc_root_ns - allocate the root profile namespace * * Returns: %0 on success else error * From 92b6d8eff55f8dca57ade26e1dde2c3b6acdae02 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:25 -0800 Subject: [PATCH 0387/1587] apparmor: allow ns visibility question to consider subnses Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 2 +- security/apparmor/include/policy_ns.h | 4 ++-- security/apparmor/policy_ns.c | 12 +++++++++--- security/apparmor/procattr.c | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 0f1a4a28e025..d7cfd79d9857 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -750,7 +750,7 @@ static int seq_show_profile(struct seq_file *f, void *p) struct aa_ns *root = f->private; if (profile->ns != root) - seq_printf(f, ":%s://", aa_ns_name(root, profile->ns)); + seq_printf(f, ":%s://", aa_ns_name(root, profile->ns, true)); seq_printf(f, "%s (%s)\n", profile->base.hname, aa_profile_mode_names[profile->mode]); diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index ebf9b40f84ed..e4c876544adc 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -74,8 +74,8 @@ extern struct aa_ns *root_ns; extern const char *aa_hidden_ns_name; -bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view); -const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child); +bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns); +const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns); void aa_free_ns(struct aa_ns *ns); int aa_alloc_root_ns(void); void aa_free_root_ns(void); diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index bab23cce197c..e7b7a829532e 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -33,18 +33,23 @@ const char *aa_hidden_ns_name = "---"; * aa_ns_visible - test if @view is visible from @curr * @curr: namespace to treat as the parent (NOT NULL) * @view: namespace to test if visible from @curr (NOT NULL) + * @subns: whether view of a subns is allowed * * Returns: true if @view is visible from @curr else false */ -bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view) +bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns) { if (curr == view) return true; + if (!subns) + return false; + for ( ; view; view = view->parent) { if (view->parent == curr) return true; } + return false; } @@ -52,16 +57,17 @@ bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view) * aa_na_name - Find the ns name to display for @view from @curr * @curr - current namespace (NOT NULL) * @view - namespace attempting to view (NOT NULL) + * @subns - are subns visible * * Returns: name of @view visible from @curr */ -const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view) +const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns) { /* if view == curr then the namespace name isn't displayed */ if (curr == view) return ""; - if (aa_ns_visible(curr, view)) { + if (aa_ns_visible(curr, view, subns)) { /* at this point if a ns is visible it is in a view ns * thus the curr ns.hname is a prefix of its name. * Only output the virtualized portion of the name diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index 15ddf74ac269..1babd3655520 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -44,10 +44,10 @@ int aa_getprocattr(struct aa_profile *profile, char **string) struct aa_ns *current_ns = __aa_current_profile()->ns; char *s; - if (!aa_ns_visible(current_ns, ns)) + if (!aa_ns_visible(current_ns, ns, true)) return -EACCES; - ns_name = aa_ns_name(current_ns, ns); + ns_name = aa_ns_name(current_ns, ns, true); ns_len = strlen(ns_name); /* if the visible ns_name is > 0 increase size for : :// seperator */ From 57e36bbd67bd1509f550311b162be78cadfe887b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:26 -0800 Subject: [PATCH 0388/1587] apparmor: add macro for bug asserts to check that a lock is held Signed-off-by: John Johansen --- security/apparmor/include/lib.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 4699c2b43fa0..61dedd7333df 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -19,6 +19,17 @@ #include "match.h" +/* Provide our own test for whether a write lock is held for asserts + * this is because on none SMP systems write_can_lock will always + * resolve to true, which is what you want for code making decisions + * based on it, but wrong for asserts checking that the lock is held + */ +#ifdef CONFIG_SMP +#define write_is_locked(X) !write_can_lock(X) +#else +#define write_is_locked(X) (1) +#endif /* CONFIG_SMP */ + /* * DEBUG remains global (no per profile flag) since it is mostly used in sysctl * which is not related to profile accesses. From 680cd62e910d7b7e3c1fcde6ba67c6ca770c2286 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:27 -0800 Subject: [PATCH 0389/1587] apparmor: add debug assert AA_BUG and Kconfig to control debug info Signed-off-by: John Johansen --- security/apparmor/Kconfig | 31 +++++++++++++++++++++++++++++-- security/apparmor/include/lib.h | 14 +++++++++++++- security/apparmor/lsm.c | 2 +- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig index be5e9414a295..b6b68a7750ce 100644 --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig @@ -36,7 +36,6 @@ config SECURITY_APPARMOR_HASH select CRYPTO select CRYPTO_SHA1 default y - help This option selects whether introspection of loaded policy is available to userspace via the apparmor filesystem. @@ -45,7 +44,6 @@ config SECURITY_APPARMOR_HASH_DEFAULT bool "Enable policy hash introspection by default" depends on SECURITY_APPARMOR_HASH default y - help This option selects whether sha1 hashing of loaded policy is enabled by default. The generation of sha1 hashes for @@ -54,3 +52,32 @@ config SECURITY_APPARMOR_HASH_DEFAULT however it can slow down policy load on some devices. In these cases policy hashing can be disabled by default and enabled only if needed. + +config SECURITY_APPARMOR_DEBUG + bool "Build AppArmor with debug code" + depends on SECURITY_APPARMOR + default n + help + Build apparmor with debugging logic in apparmor. Not all + debugging logic will necessarily be enabled. A submenu will + provide fine grained control of the debug options that are + available. + +config SECURITY_APPARMOR_DEBUG_ASSERTS + bool "Build AppArmor with debugging asserts" + depends on SECURITY_APPARMOR_DEBUG + default y + help + Enable code assertions made with AA_BUG. These are primarily + function entry preconditions but also exist at other key + points. If the assert is triggered it will trigger a WARN + message. + +config SECURITY_APPARMOR_DEBUG_MESSAGES + bool "Debug messages enabled by default" + depends on SECURITY_APPARMOR_DEBUG + default n + help + Set the default value of the apparmor.debug kernel parameter. + When enabled, various debug messages will be logged to + the kernel message buffer. diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 61dedd7333df..d507c73ac9b8 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -35,12 +35,24 @@ * which is not related to profile accesses. */ +#define DEBUG_ON (aa_g_debug) +#define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args) #define AA_DEBUG(fmt, args...) \ do { \ - if (aa_g_debug) \ + if (DEBUG_ON) \ pr_debug_ratelimited("AppArmor: " fmt, ##args); \ } while (0) +#define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __func__, #X) + +#define AA_BUG(X, args...) AA_BUG_FMT((X), "" args) +#ifdef CONFIG_SECURITY_APPARMOR_DEBUG_ASSERTS +#define AA_BUG_FMT(X, fmt, args...) \ + WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __func__, ##args) +#else +#define AA_BUG_FMT(X, fmt, args...) +#endif + #define AA_ERROR(fmt, args...) \ pr_err_ratelimited("AppArmor: " fmt, ##args) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 1dae66ba757b..99a6e5ec4ffe 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -681,7 +681,7 @@ module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); #endif /* Debug mode */ -bool aa_g_debug; +bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_DEBUG_MESSAGES); module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR); /* Audit mode */ From efeee83a7060c225fac5ac794e9c11183c267f81 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:28 -0800 Subject: [PATCH 0390/1587] apparmor: rename mediated_filesystem() to path_mediated_fs() Rename to indicate the test is only about whether path mediation is used, not whether other types of mediation might be used. Signed-off-by: John Johansen --- security/apparmor/include/lib.h | 2 +- security/apparmor/lsm.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index d507c73ac9b8..4ff09ed813b5 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -111,7 +111,7 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, return aa_dfa_next(dfa, start, 0); } -static inline bool mediated_filesystem(struct dentry *dentry) +static inline bool path_mediated_fs(struct dentry *dentry) { return !(dentry->d_sb->s_flags & MS_NOUSER); } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 99a6e5ec4ffe..a757c163fda6 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -195,7 +195,7 @@ static inline int common_perm_path(int op, const struct path *path, u32 mask) struct path_cond cond = { d_backing_inode(path->dentry)->i_uid, d_backing_inode(path->dentry)->i_mode }; - if (!mediated_filesystem(path->dentry)) + if (!path_mediated_fs(path->dentry)) return 0; return common_perm(op, path, mask, &cond); @@ -216,7 +216,7 @@ static int common_perm_rm(int op, const struct path *dir, struct inode *inode = d_backing_inode(dentry); struct path_cond cond = { }; - if (!inode || !mediated_filesystem(dentry)) + if (!inode || !path_mediated_fs(dentry)) return 0; cond.uid = inode->i_uid; @@ -240,7 +240,7 @@ static int common_perm_create(int op, const struct path *dir, { struct path_cond cond = { current_fsuid(), mode }; - if (!mediated_filesystem(dir->dentry)) + if (!path_mediated_fs(dir->dentry)) return 0; return common_perm_dir_dentry(op, dir, dentry, mask, &cond); @@ -287,7 +287,7 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_ struct aa_profile *profile; int error = 0; - if (!mediated_filesystem(old_dentry)) + if (!path_mediated_fs(old_dentry)) return 0; profile = aa_current_profile(); @@ -302,7 +302,7 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d struct aa_profile *profile; int error = 0; - if (!mediated_filesystem(old_dentry)) + if (!path_mediated_fs(old_dentry)) return 0; profile = aa_current_profile(); @@ -349,7 +349,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) struct aa_profile *profile; int error = 0; - if (!mediated_filesystem(file->f_path.dentry)) + if (!path_mediated_fs(file->f_path.dentry)) return 0; /* If in exec, permission is handled by bprm hooks. @@ -402,7 +402,7 @@ static int common_file_perm(int op, struct file *file, u32 mask) BUG_ON(!fprofile); if (!file->f_path.mnt || - !mediated_filesystem(file->f_path.dentry)) + !path_mediated_fs(file->f_path.dentry)) return 0; profile = __aa_current_profile(); From 6e474e3063eae9767f219d83cf91d8360f63be0c Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:29 -0800 Subject: [PATCH 0391/1587] apparmor: rename hname_tail to basename Rename to the shorter and more familiar shell cmd name Signed-off-by: John Johansen --- security/apparmor/include/lib.h | 4 ++-- security/apparmor/lib.c | 2 +- security/apparmor/policy.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 4ff09ed813b5..b5c16d3a7a18 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -130,12 +130,12 @@ struct aa_policy { }; /** - * hname_tail - find the last component of an hname + * basename - find the last component of an hname * @name: hname to find the base profile name component of (NOT NULL) * * Returns: the tail (base profile name) name component of an hname */ -static inline const char *hname_tail(const char *hname) +static inline const char *basename(const char *hname) { char *split; diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index fec78eecce0d..02203889c3c8 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -184,7 +184,7 @@ bool aa_policy_init(struct aa_policy *policy, const char *prefix, if (!policy->hname) return 0; /* base.name is a substring of fqname */ - policy->name = (char *)hname_tail(policy->hname); + policy->name = (char *)basename(policy->hname); INIT_LIST_HEAD(&policy->list); INIT_LIST_HEAD(&policy->profiles); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 7fde5785005d..3b23960b8a5d 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -617,7 +617,7 @@ bool aa_may_manage_policy(int op) static struct aa_profile *__list_lookup_parent(struct list_head *lh, struct aa_profile *profile) { - const char *base = hname_tail(profile->base.hname); + const char *base = basename(profile->base.hname); long len = base - profile->base.hname; struct aa_load_ent *ent; From bbe4a7c8733c925b061dcce2d1af8926cefbe539 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:30 -0800 Subject: [PATCH 0392/1587] apparmor: constify policy name and hname Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 2 +- security/apparmor/include/lib.h | 4 ++-- security/apparmor/lib.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index d7cfd79d9857..96a02ee9c499 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -38,7 +38,7 @@ * * Returns: length of mangled name */ -static int mangle_name(char *name, char *target) +static int mangle_name(const char *name, char *target) { char *t = target; diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index b5c16d3a7a18..7e81cdab4af0 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -123,8 +123,8 @@ static inline bool path_mediated_fs(struct dentry *dentry) * @profiles: head of the profiles list contained in the object */ struct aa_policy { - char *name; - char *hname; + const char *name; + const char *hname; struct list_head list; struct list_head profiles; }; diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 02203889c3c8..91d5766d1c28 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -178,7 +178,7 @@ bool aa_policy_init(struct aa_policy *policy, const char *prefix, policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, GFP_KERNEL); if (policy->hname) - sprintf(policy->hname, "%s//%s", prefix, name); + sprintf((char *)policy->hname, "%s//%s", prefix, name); } else policy->hname = kstrdup(name, GFP_KERNEL); if (!policy->hname) From d102d895713c736fd13e21feaab38b52d8ab32ad Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:31 -0800 Subject: [PATCH 0393/1587] apparmor: pass gfp param into aa_policy_init() Signed-off-by: John Johansen --- security/apparmor/include/lib.h | 2 +- security/apparmor/lib.c | 8 ++++---- security/apparmor/policy.c | 2 +- security/apparmor/policy_ns.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 7e81cdab4af0..fa281c272970 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -194,7 +194,7 @@ static inline struct aa_policy *__policy_strn_find(struct list_head *head, } bool aa_policy_init(struct aa_policy *policy, const char *prefix, - const char *name); + const char *name, gfp_t gfp); void aa_policy_destroy(struct aa_policy *policy); #endif /* AA_LIB_H */ diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 91d5766d1c28..bcd598c7ca9d 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -171,20 +171,20 @@ void *__aa_kvmalloc(size_t size, gfp_t flags) * Returns: true if policy init successful */ bool aa_policy_init(struct aa_policy *policy, const char *prefix, - const char *name) + const char *name, gfp_t gfp) { /* freed by policy_free */ if (prefix) { policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, - GFP_KERNEL); + gfp); if (policy->hname) sprintf((char *)policy->hname, "%s//%s", prefix, name); } else - policy->hname = kstrdup(name, GFP_KERNEL); + policy->hname = kstrdup(name, gfp); if (!policy->hname) return 0; /* base.name is a substring of fqname */ - policy->name = (char *)basename(policy->hname); + policy->name = basename(policy->hname); INIT_LIST_HEAD(&policy->list); INIT_LIST_HEAD(&policy->profiles); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 3b23960b8a5d..5d99fb7ac881 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -272,7 +272,7 @@ struct aa_profile *aa_alloc_profile(const char *hname) goto fail; kref_init(&profile->proxy->count); - if (!aa_policy_init(&profile->base, NULL, hname)) + if (!aa_policy_init(&profile->base, NULL, hname, GFP_KERNEL)) goto fail; kref_init(&profile->count); diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index e7b7a829532e..8a5632f39751 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -95,7 +95,7 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) AA_DEBUG("%s(%p)\n", __func__, ns); if (!ns) return NULL; - if (!aa_policy_init(&ns->base, prefix, name)) + if (!aa_policy_init(&ns->base, prefix, name, GFP_KERNEL)) goto fail_ns; INIT_LIST_HEAD(&ns->sub_ns); From 5fd1b95fc9b96629d185f5fe3d9342fcff78eb30 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:32 -0800 Subject: [PATCH 0394/1587] apparmor: update policy_destroy to use new debug asserts Signed-off-by: John Johansen --- security/apparmor/lib.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index bcd598c7ca9d..5d8ef31a60f1 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -197,15 +197,8 @@ bool aa_policy_init(struct aa_policy *policy, const char *prefix, */ void aa_policy_destroy(struct aa_policy *policy) { - /* still contains profiles -- invalid */ - if (on_list_rcu(&policy->profiles)) { - AA_ERROR("%s: internal error, policy '%s' contains profiles\n", - __func__, policy->name); - } - if (on_list_rcu(&policy->list)) { - AA_ERROR("%s: internal error, policy '%s' still on list\n", - __func__, policy->name); - } + AA_BUG(on_list_rcu(&policy->profiles)); + AA_BUG(on_list_rcu(&policy->list)); /* don't free name as its a subset of hname */ kzfree(policy->hname); From 73688d1ed0b8f800f312f7bc9d583463858da861 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:34 -0800 Subject: [PATCH 0395/1587] apparmor: refactor prepare_ns() and make usable from different views prepare_ns() will need to be called from alternate views, and namespaces will need to be created via different interfaces. So refactor and allow specifying the view ns. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 6 +- security/apparmor/include/policy.h | 3 +- security/apparmor/include/policy_ns.h | 4 +- security/apparmor/policy.c | 6 +- security/apparmor/policy_ns.c | 102 +++++++++++++++++--------- 5 files changed, 81 insertions(+), 40 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 96a02ee9c499..2b48be2169cb 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -125,7 +125,8 @@ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, error = PTR_ERR(data); if (!IS_ERR(data)) { - error = aa_replace_profiles(data, size, PROF_ADD); + error = aa_replace_profiles(__aa_current_profile()->ns, data, + size, PROF_ADD); kvfree(data); } @@ -147,7 +148,8 @@ static ssize_t profile_replace(struct file *f, const char __user *buf, data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos); error = PTR_ERR(data); if (!IS_ERR(data)) { - error = aa_replace_profiles(data, size, PROF_REPLACE); + error = aa_replace_profiles(__aa_current_profile()->ns, data, + size, PROF_REPLACE); kvfree(data); } diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index da62d29d3992..1573cade8812 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -184,7 +184,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, const char *fqname, size_t n); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); -ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); +ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, + bool noreplace); ssize_t aa_remove_profiles(char *name, size_t size); void __aa_profile_list_release(struct list_head *head); diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index e4c876544adc..820d86d266fe 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -83,7 +83,9 @@ void aa_free_ns_kref(struct kref *kref); struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name); struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n); -struct aa_ns *aa_prepare_ns(const char *name); +struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name, + struct dentry *dir); +struct aa_ns *aa_prepare_ns(struct aa_ns *root, const char *name); void __aa_remove_ns(struct aa_ns *ns); static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 5d99fb7ac881..e02ab20b0a8d 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -731,6 +731,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, /** * aa_replace_profiles - replace profile(s) on the profile list + * @view: namespace load is viewed from * @udata: serialized data stream (NOT NULL) * @size: size of the serialized data stream * @noreplace: true if only doing addition, no replacement allowed @@ -741,7 +742,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, * * Returns: size of data consumed else error code on failure. */ -ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) +ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, + bool noreplace) { const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; @@ -756,7 +758,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) goto out; /* released below */ - ns = aa_prepare_ns(ns_name); + ns = aa_prepare_ns(view, ns_name); if (!ns) { error = audit_policy(op, GFP_KERNEL, ns_name, "failed to prepare namespace", -ENOMEM); diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 8a5632f39751..f6cdc738ffcd 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -181,48 +181,82 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) return aa_findn_ns(root, name, strlen(name)); } +static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, + struct dentry *dir) +{ + struct aa_ns *ns; + int error; + + AA_BUG(!parent); + AA_BUG(!name); + AA_BUG(!mutex_is_locked(&parent->lock)); + + ns = alloc_ns(parent->base.hname, name); + if (!ns) + return NULL; + mutex_lock(&ns->lock); + error = __aa_fs_ns_mkdir(ns, ns_subns_dir(parent), name); + if (error) { + AA_ERROR("Failed to create interface for ns %s\n", + ns->base.name); + mutex_unlock(&ns->lock); + aa_free_ns(ns); + return ERR_PTR(error); + } + ns->parent = aa_get_ns(parent); + list_add_rcu(&ns->base.list, &parent->sub_ns); + /* add list ref */ + aa_get_ns(ns); + mutex_unlock(&ns->lock); + + return ns; +} + +/** + * aa_create_ns - create an ns, fail if it already exists + * @parent: the parent of the namespace being created + * @name: the name of the namespace + * @dir: if not null the dir to put the ns entries in + * + * Returns: the a refcounted ns that has been add or an ERR_PTR + */ +struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name, + struct dentry *dir) +{ + struct aa_ns *ns; + + AA_BUG(!mutex_is_locked(&parent->lock)); + + /* try and find the specified ns */ + /* released by caller */ + ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); + if (!ns) + ns = __aa_create_ns(parent, name, dir); + else + ns = ERR_PTR(-EEXIST); + + /* return ref */ + return ns; +} + /** * aa_prepare_ns - find an existing or create a new namespace of @name - * @name: the namespace to find or add (MAYBE NULL) + * @parent: ns to treat as parent + * @name: the namespace to find or add (NOT NULL) * - * Returns: refcounted ns or NULL if failed to create one + * Returns: refcounted namespace or PTR_ERR if failed to create one */ -struct aa_ns *aa_prepare_ns(const char *name) +struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name) { - struct aa_ns *ns, *root; - - root = aa_current_profile()->ns; - - mutex_lock(&root->lock); - - /* if name isn't specified the profile is loaded to the current ns */ - if (!name) { - /* released by caller */ - ns = aa_get_ns(root); - goto out; - } + struct aa_ns *ns; + mutex_lock(&parent->lock); /* try and find the specified ns and if it doesn't exist create it */ /* released by caller */ - ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name)); - if (!ns) { - ns = alloc_ns(root->base.hname, name); - if (!ns) - goto out; - if (__aa_fs_ns_mkdir(ns, ns_subns_dir(root), name)) { - AA_ERROR("Failed to create interface for ns %s\n", - ns->base.name); - aa_free_ns(ns); - ns = NULL; - goto out; - } - ns->parent = aa_get_ns(root); - list_add_rcu(&ns->base.list, &root->sub_ns); - /* add list ref */ - aa_get_ns(ns); - } -out: - mutex_unlock(&root->lock); + ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); + if (!ns) + ns = __aa_create_ns(parent, name, NULL); + mutex_unlock(&parent->lock); /* return ref */ return ns; From 30b026a8d16bfa15bc24f4cca1604e47ac1a2f64 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:35 -0800 Subject: [PATCH 0396/1587] apparmor: pass gfp_t parameter into profile allocation Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 2 +- security/apparmor/policy.c | 11 ++++++----- security/apparmor/policy_ns.c | 2 +- security/apparmor/policy_unpack.c | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 1573cade8812..b44eaea2bd2c 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -172,7 +172,7 @@ void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); void aa_free_proxy_kref(struct kref *kref); -struct aa_profile *aa_alloc_profile(const char *name); +struct aa_profile *aa_alloc_profile(const char *name, gfp_t gfp); struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index e02ab20b0a8d..e310f3b63fbe 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -255,24 +255,25 @@ void aa_free_profile_kref(struct kref *kref) /** * aa_alloc_profile - allocate, initialize and return a new profile * @hname: name of the profile (NOT NULL) + * @gfp: allocation type * * Returns: refcount profile or NULL on failure */ -struct aa_profile *aa_alloc_profile(const char *hname) +struct aa_profile *aa_alloc_profile(const char *hname, gfp_t gfp) { struct aa_profile *profile; /* freed by free_profile - usually through aa_put_profile */ - profile = kzalloc(sizeof(*profile), GFP_KERNEL); + profile = kzalloc(sizeof(*profile), gfp); if (!profile) return NULL; - profile->proxy = kzalloc(sizeof(struct aa_proxy), GFP_KERNEL); + profile->proxy = kzalloc(sizeof(struct aa_proxy), gfp); if (!profile->proxy) goto fail; kref_init(&profile->proxy->count); - if (!aa_policy_init(&profile->base, NULL, hname, GFP_KERNEL)) + if (!aa_policy_init(&profile->base, NULL, hname, gfp)) goto fail; kref_init(&profile->count); @@ -312,7 +313,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) goto fail; sprintf(name, "%s//null-%x", parent->base.hname, uniq); - profile = aa_alloc_profile(name); + profile = aa_alloc_profile(name, GFP_KERNEL); kfree(name); if (!profile) goto fail; diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index f6cdc738ffcd..1e19bd3c7851 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -102,7 +102,7 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) mutex_init(&ns->lock); /* released by aa_free_ns() */ - ns->unconfined = aa_alloc_profile("unconfined"); + ns->unconfined = aa_alloc_profile("unconfined", GFP_KERNEL); if (!ns->unconfined) goto fail_unconfined; diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 138120698f83..9ddc6b2a7322 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -486,7 +486,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) if (!unpack_str(e, &name, NULL)) goto fail; - profile = aa_alloc_profile(name); + profile = aa_alloc_profile(name, GFP_KERNEL); if (!profile) return ERR_PTR(-ENOMEM); From 181f7c977680dcd86eb71ad4b37239d2a385c3ad Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:36 -0800 Subject: [PATCH 0397/1587] apparmor: name null-XXX profiles after the executable When possible its better to name a learning profile after the missing profile in question. This allows for both more informative names and for profile reuse. Signed-off-by: John Johansen --- security/apparmor/domain.c | 8 +++-- security/apparmor/include/policy.h | 3 +- security/apparmor/policy.c | 53 ++++++++++++++++++++++-------- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 503cb2c54447..1a8ffc577009 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -442,7 +442,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) } } else if (COMPLAIN_MODE(profile)) { /* no exec permission - are we in learning mode */ - new_profile = aa_new_null_profile(profile, 0); + new_profile = aa_new_null_profile(profile, false, name, + GFP_ATOMIC); if (!new_profile) { error = -ENOMEM; info = "could not create null profile"; @@ -667,7 +668,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) aa_put_profile(root); target = name; /* released below */ - hat = aa_new_null_profile(profile, 1); + hat = aa_new_null_profile(profile, true, hats[0], + GFP_KERNEL); if (!hat) { info = "failed null profile create"; error = -ENOMEM; @@ -815,7 +817,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, if (permtest || !COMPLAIN_MODE(profile)) goto audit; /* released below */ - target = aa_new_null_profile(profile, 0); + target = aa_new_null_profile(profile, false, hname, GFP_KERNEL); if (!target) { info = "failed null profile create"; error = -ENOMEM; diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index b44eaea2bd2c..3527e3f5a099 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -173,7 +173,8 @@ void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); void aa_free_proxy_kref(struct kref *kref); struct aa_profile *aa_alloc_profile(const char *name, gfp_t gfp); -struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); +struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, + const char *base, gfp_t gfp); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index e310f3b63fbe..dd63ac92d28f 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -288,12 +288,16 @@ fail: } /** - * aa_new_null_profile - create a new null-X learning profile + * aa_new_null_profile - create or find a null-X learning profile * @parent: profile that caused this profile to be created (NOT NULL) * @hat: true if the null- learning profile is a hat + * @base: name to base the null profile off of + * @gfp: type of allocation * - * Create a null- complain mode profile used in learning mode. The name of - * the profile is unique and follows the format of parent//null-. + * Find/Create a null- complain mode profile used in learning mode. The + * name of the profile is unique and follows the format of parent//null-XXX. + * where XXX is based on the @name or if that fails or is not supplied + * a unique number * * null profiles are added to the profile list but the list does not * hold a count on them so that they are automatically released when @@ -301,27 +305,45 @@ fail: * * Returns: new refcounted profile else NULL on failure */ -struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) +struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, + const char *base, gfp_t gfp) { - struct aa_profile *profile = NULL; + struct aa_profile *profile; char *name; - int uniq = atomic_inc_return(&parent->ns->uniq_null); - /* freed below */ - name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL); + AA_BUG(!parent); + + if (base) { + name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base), + gfp); + if (name) { + sprintf(name, "%s//null-%s", parent->base.hname, base); + goto name; + } + /* fall through to try shorter uniq */ + } + + name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp); if (!name) - goto fail; - sprintf(name, "%s//null-%x", parent->base.hname, uniq); + return NULL; + sprintf(name, "%s//null-%x", parent->base.hname, + atomic_inc_return(&parent->ns->uniq_null)); - profile = aa_alloc_profile(name, GFP_KERNEL); - kfree(name); +name: + /* lookup to see if this is a dup creation */ + profile = aa_find_child(parent, basename(name)); + if (profile) + goto out; + + profile = aa_alloc_profile(name, gfp); if (!profile) goto fail; profile->mode = APPARMOR_COMPLAIN; - profile->flags = PFLAG_NULL; + profile->flags |= PFLAG_NULL; if (hat) profile->flags |= PFLAG_HAT; + profile->path_flags = parent->path_flags; /* released on free_profile */ rcu_assign_pointer(profile->parent, aa_get_profile(parent)); @@ -332,9 +354,14 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) mutex_unlock(&profile->ns->lock); /* refcount released by caller */ +out: + kfree(name); + return profile; fail: + kfree(name); + aa_free_profile(profile); return NULL; } From abbf8734039fe57c72c999e37bd1c30d8aed1943 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:37 -0800 Subject: [PATCH 0398/1587] apparmor: remove paranoid load switch Policy should always under go a full paranoid verification. Signed-off-by: John Johansen --- security/apparmor/lsm.c | 5 +++-- security/apparmor/policy_unpack.c | 21 +++++++-------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index a757c163fda6..e40eecbbaefa 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -714,10 +714,11 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR); /* Determines how paranoid loading of policy is and how much verification * on the loaded policy is done. + * DEPRECATED: read only as strict checking of load is always done now + * that none root users (user namespaces) can load policy. */ bool aa_g_paranoid_load = 1; -module_param_named(paranoid_load, aa_g_paranoid_load, aabool, - S_IRUSR | S_IWUSR); +module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); /* Boot time disable flag */ static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE; diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 9ddc6b2a7322..fe73117cd940 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -340,12 +340,7 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e) ((e->pos - e->start) & 7); size_t pad = ALIGN(sz, 8) - sz; int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | - TO_ACCEPT2_FLAG(YYTD_DATA32); - - - if (aa_g_paranoid_load) - flags |= DFA_FLAG_VERIFY_STATES; - + TO_ACCEPT2_FLAG(YYTD_DATA32) | DFA_FLAG_VERIFY_STATES; dfa = aa_dfa_unpack(blob + pad, size - pad, flags); if (IS_ERR(dfa)) @@ -705,14 +700,12 @@ static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size) */ static int verify_profile(struct aa_profile *profile) { - if (aa_g_paranoid_load) { - if (profile->file.dfa && - !verify_dfa_xindex(profile->file.dfa, - profile->file.trans.size)) { - audit_iface(profile, NULL, "Invalid named transition", - NULL, -EPROTO); - return -EPROTO; - } + if (profile->file.dfa && + !verify_dfa_xindex(profile->file.dfa, + profile->file.trans.size)) { + audit_iface(profile, NULL, "Invalid named transition", + NULL, -EPROTO); + return -EPROTO; } return 0; From 5ebfb12822656beec5c56b362d44e4db81c8e1eb Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:38 -0800 Subject: [PATCH 0399/1587] apparmor: add support for force complain flag to support learning mode Signed-off-by: John Johansen --- security/apparmor/policy_unpack.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index fe73117cd940..c836a9c8b6ff 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -29,6 +29,8 @@ #include "include/policy.h" #include "include/policy_unpack.h" +#define FORCE_COMPLAIN_FLAG 0x800 + /* * The AppArmor interface treats data as a type byte followed by the * actual data. The interface has the notion of a a named entry @@ -514,7 +516,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) profile->flags |= PFLAG_HAT; if (!unpack_u32(e, &tmp, NULL)) goto fail; - if (tmp == PACKED_MODE_COMPLAIN) + if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) profile->mode = APPARMOR_COMPLAIN; else if (tmp == PACKED_MODE_KILL) profile->mode = APPARMOR_KILL; From 474d6b75106229025ab6b7bbabf2f9c246e928e1 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:39 -0800 Subject: [PATCH 0400/1587] apparmor: prepare to support newer versions of policy Newer policy encodes more than just version in the version tag, so add masking to make sure the comparison remains correct. Note: this is fully compatible with older policy as it will never set the bits being masked out. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 10 ++++++++-- security/apparmor/policy_unpack.c | 25 +++++++++++++++++-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 2b48be2169cb..49a5122e03fe 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -799,9 +799,15 @@ static struct aa_fs_entry aa_fs_entry_domain[] = { { } }; +static struct aa_fs_entry aa_fs_entry_versions[] = { + AA_FS_FILE_BOOLEAN("v5", 1), + { } +}; + static struct aa_fs_entry aa_fs_entry_policy[] = { - AA_FS_FILE_BOOLEAN("set_load", 1), - {} + AA_FS_DIR("versions", aa_fs_entry_versions), + AA_FS_FILE_BOOLEAN("set_load", 1), + { } }; static struct aa_fs_entry aa_fs_entry_features[] = { diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index c836a9c8b6ff..6ac292fec55f 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -29,7 +29,14 @@ #include "include/policy.h" #include "include/policy_unpack.h" +#define K_ABI_MASK 0x3ff #define FORCE_COMPLAIN_FLAG 0x800 +#define VERSION_LT(X, Y) (((X) & K_ABI_MASK) < ((Y) & K_ABI_MASK)) +#define VERSION_GT(X, Y) (((X) & K_ABI_MASK) > ((Y) & K_ABI_MASK)) + +#define v5 5 /* base version */ +#define v6 6 /* per entry policydb mediation check */ +#define v7 7 /* full network masking */ /* * The AppArmor interface treats data as a type byte followed by the @@ -646,19 +653,21 @@ static int verify_header(struct aa_ext *e, int required, const char **ns) /* get the interface version */ if (!unpack_u32(e, &e->version, "version")) { if (required) { - audit_iface(NULL, NULL, "invalid profile format", e, - error); - return error; - } - - /* check that the interface version is currently supported */ - if (e->version != 5) { - audit_iface(NULL, NULL, "unsupported interface version", + audit_iface(NULL, NULL, "invalid profile format", e, error); return error; } } + /* Check that the interface version is currently supported. + * if not specified use previous version + * Mask off everything that is not kernel abi version + */ + if (VERSION_LT(e->version, v5) && VERSION_GT(e->version, v7)) { + audit_iface(NULL, NULL, "unsupported interface version", + e, error); + return error; + } /* read the namespace if present */ if (unpack_str(e, &name, "namespace")) { From 293a4886f93f1d4f01ef2642b81c2509a5376ce5 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:40 -0800 Subject: [PATCH 0401/1587] apparmor: add get_dfa() fn The dfa is currently setup to be shared (has the basis of refcounting) but currently can't be because the count can't be increased. Signed-off-by: John Johansen --- security/apparmor/include/match.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index a1c04fe86790..d751c8bf72cd 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -127,6 +127,21 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, void aa_dfa_free_kref(struct kref *kref); +/** + * aa_get_dfa - increment refcount on dfa @p + * @dfa: dfa (MAYBE NULL) + * + * Returns: pointer to @dfa if @dfa is NULL will return NULL + * Requires: @dfa must be held with valid refcount when called + */ +static inline struct aa_dfa *aa_get_dfa(struct aa_dfa *dfa) +{ + if (dfa) + kref_get(&(dfa->count)); + + return dfa; +} + /** * aa_put_dfa - put a dfa refcount * @dfa: dfa to put refcount (MAYBE NULL) From 6604d4c1c1a65d3d1a6a56291d96516d1e9b7041 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:41 -0800 Subject: [PATCH 0402/1587] apparmor: allow policydb to be used as the file dfa Newer policy will combine the file and policydb dfas, allowing for better optimizations. However to support older policy we need to keep the ability to address the "file" dfa separately. So dup the policydb as if it is the file dfa and set the appropriate start state. Signed-off-by: John Johansen --- security/apparmor/policy_unpack.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 6ac292fec55f..7160addb11be 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -611,12 +611,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) error = PTR_ERR(profile->file.dfa); profile->file.dfa = NULL; goto fail; + } else if (profile->file.dfa) { + if (!unpack_u32(e, &profile->file.start, "dfa_start")) + /* default start state */ + profile->file.start = DFA_START; + } else if (profile->policy.dfa && + profile->policy.start[AA_CLASS_FILE]) { + profile->file.dfa = aa_get_dfa(profile->policy.dfa); + profile->file.start = profile->policy.start[AA_CLASS_FILE]; } - if (!unpack_u32(e, &profile->file.start, "dfa_start")) - /* default start state */ - profile->file.start = DFA_START; - if (!unpack_trans_table(e, profile)) goto fail; From 11c236b89d7c26d58c55d5613a858600a4d2ab3a Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:42 -0800 Subject: [PATCH 0403/1587] apparmor: add a default null dfa Instead of testing whether a given dfa exists in every code path, have a default null dfa that is used when loaded policy doesn't provide a dfa. This will let us get rid of special casing and avoid dereference bugs when special casing is missed. Signed-off-by: John Johansen --- security/apparmor/include/match.h | 5 +++++ security/apparmor/lsm.c | 7 +++++++ security/apparmor/match.c | 27 +++++++++++++++++++++++++++ security/apparmor/nulldfa.in | 1 + security/apparmor/policy.c | 2 ++ security/apparmor/policy_unpack.c | 6 ++++-- 6 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 security/apparmor/nulldfa.in diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index d751c8bf72cd..a85bb3b1836c 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -100,6 +100,8 @@ struct aa_dfa { struct table_header *tables[YYTD_ID_TSIZE]; }; +extern struct aa_dfa *nulldfa; + #define byte_to_byte(X) (X) #define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \ @@ -117,6 +119,9 @@ static inline size_t table_size(size_t len, size_t el_size) return ALIGN(sizeof(struct table_header) + len * el_size, 8); } +int aa_setup_dfa_engine(void); +void aa_teardown_dfa_engine(void); + struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags); unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, const char *str, int len); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index e40eecbbaefa..f852cd626f2e 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -878,6 +878,12 @@ static int __init apparmor_init(void) return 0; } + error = aa_setup_dfa_engine(); + if (error) { + AA_ERROR("Unable to setup dfa engine\n"); + goto alloc_out; + } + error = aa_alloc_root_ns(); if (error) { AA_ERROR("Unable to allocate default profile namespace\n"); @@ -905,6 +911,7 @@ static int __init apparmor_init(void) alloc_out: aa_destroy_aafs(); + aa_teardown_dfa_engine(); apparmor_enabled = 0; return error; diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 0e04bcf91154..8f0806b35a75 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -25,6 +25,33 @@ #define base_idx(X) ((X) & 0xffffff) +static char nulldfa_src[] = { + #include "nulldfa.in" +}; +struct aa_dfa *nulldfa; + +int aa_setup_dfa_engine(void) +{ + int error; + + nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), + TO_ACCEPT1_FLAG(YYTD_DATA32) | + TO_ACCEPT2_FLAG(YYTD_DATA32)); + if (!IS_ERR(nulldfa)) + return 0; + + error = PTR_ERR(nulldfa); + nulldfa = NULL; + + return error; +} + +void aa_teardown_dfa_engine(void) +{ + aa_put_dfa(nulldfa); + nulldfa = NULL; +} + /** * unpack_table - unpack a dfa table (one of accept, default, base, next check) * @blob: data to unpack (NOT NULL) diff --git a/security/apparmor/nulldfa.in b/security/apparmor/nulldfa.in new file mode 100644 index 000000000000..3cb38022902e --- /dev/null +++ b/security/apparmor/nulldfa.in @@ -0,0 +1 @@ +0x1B, 0x5E, 0x78, 0x3D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x04, 0x90, 0x00, 0x00, 0x6E, 0x6F, 0x74, 0x66, 0x6C, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index dd63ac92d28f..046edecc4c8a 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -348,6 +348,8 @@ name: /* released on free_profile */ rcu_assign_pointer(profile->parent, aa_get_profile(parent)); profile->ns = aa_get_ns(parent->ns); + profile->file.dfa = aa_get_dfa(nulldfa); + profile->policy.dfa = aa_get_dfa(nulldfa); mutex_lock(&profile->ns->lock); __list_add_profile(&parent->base.profiles, profile); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 7160addb11be..51a7f9fc8a3e 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -603,7 +603,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) } if (!unpack_nameX(e, AA_STRUCTEND, NULL)) goto fail; - } + } else + profile->policy.dfa = aa_get_dfa(nulldfa); /* get file rules */ profile->file.dfa = unpack_dfa(e); @@ -619,7 +620,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) profile->policy.start[AA_CLASS_FILE]) { profile->file.dfa = aa_get_dfa(profile->policy.dfa); profile->file.start = profile->policy.start[AA_CLASS_FILE]; - } + } else + profile->file.dfa = aa_get_dfa(nulldfa); if (!unpack_trans_table(e, profile)) goto fail; From 34c426acb75cc21bdf84685e106db0c1a3565057 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:43 -0800 Subject: [PATCH 0404/1587] apparmor: provide userspace flag indicating binfmt_elf_mmap change Commit 9f834ec18def ("binfmt_elf: switch to new creds when switching to new mm") changed when the creds are installed by the binfmt_elf handler. This affects which creds are used to mmap the executable into the address space. Which can have an affect on apparmor policy. Add a flag to apparmor at /sys/kernel/security/apparmor/features/domain/fix_binfmt_elf_mmap to make it possible to detect this semantic change so that the userspace tools and the regression test suite can correctly deal with the change. BugLink: http://bugs.launchpad.net/bugs/1630069 Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 49a5122e03fe..5c000cb7ef8e 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -796,6 +796,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = { AA_FS_FILE_BOOLEAN("change_hatv", 1), AA_FS_FILE_BOOLEAN("change_onexec", 1), AA_FS_FILE_BOOLEAN("change_profile", 1), + AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1), { } }; From a71ada305801e940ff69c2c58489778760e5148b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:45 -0800 Subject: [PATCH 0405/1587] apparmor: add special .null file used to "close" fds at exec Borrow the special null device file from selinux to "close" fds that don't have sufficient permissions at exec time. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 78 +++++++++++++++++++++++++- security/apparmor/include/apparmorfs.h | 2 + security/apparmor/include/policy_ns.h | 2 + 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 5c000cb7ef8e..2501a65fe7d3 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -18,9 +18,12 @@ #include #include #include +#include #include #include #include +#include +#include #include "include/apparmor.h" #include "include/apparmorfs.h" @@ -352,6 +355,28 @@ static const struct file_operations aa_fs_seq_hash_fops = { .release = single_release, }; +static int aa_fs_seq_show_ns_level(struct seq_file *seq, void *v) +{ + struct aa_ns *ns = aa_current_profile()->ns; + + seq_printf(seq, "%d\n", ns->level); + + return 0; +} + +static int aa_fs_seq_open_ns_level(struct inode *inode, struct file *file) +{ + return single_open(file, aa_fs_seq_show_ns_level, inode->i_private); +} + +static const struct file_operations aa_fs_ns_level = { + .owner = THIS_MODULE, + .open = aa_fs_seq_open_ns_level, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /** fns to setup dynamic per profile/namespace files **/ void __aa_fs_profile_rmdir(struct aa_profile *profile) { @@ -825,6 +850,7 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = { AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load), AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), + AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level), AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops), AA_FS_DIR("features", aa_fs_entry_features), { } @@ -934,6 +960,52 @@ void __init aa_destroy_aafs(void) aafs_remove_dir(&aa_fs_entry); } + +#define NULL_FILE_NAME ".null" +struct path aa_null; + +static int aa_mk_null_file(struct dentry *parent) +{ + struct vfsmount *mount = NULL; + struct dentry *dentry; + struct inode *inode; + int count = 0; + int error = simple_pin_fs(parent->d_sb->s_type, &mount, &count); + + if (error) + return error; + + inode_lock(d_inode(parent)); + dentry = lookup_one_len(NULL_FILE_NAME, parent, strlen(NULL_FILE_NAME)); + if (IS_ERR(dentry)) { + error = PTR_ERR(dentry); + goto out; + } + inode = new_inode(parent->d_inode->i_sb); + if (!inode) { + error = -ENOMEM; + goto out1; + } + + inode->i_ino = get_next_ino(); + inode->i_mode = S_IFCHR | S_IRUGO | S_IWUGO; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, + MKDEV(MEM_MAJOR, 3)); + d_instantiate(dentry, inode); + aa_null.dentry = dget(dentry); + aa_null.mnt = mntget(mount); + + error = 0; + +out1: + dput(dentry); +out: + inode_unlock(d_inode(parent)); + simple_release_fs(&mount, &count); + return error; +} + /** * aa_create_aafs - create the apparmor security filesystem * @@ -962,7 +1034,11 @@ static int __init aa_create_aafs(void) if (error) goto error; - /* TODO: add support for apparmorfs_null and apparmorfs_mnt */ + error = aa_mk_null_file(aa_fs_entry.dentry); + if (error) + goto error; + + /* TODO: add default profile to apparmorfs */ /* Report that AppArmor fs is enabled */ aa_info_message("AppArmor Filesystem Enabled"); diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index 5626bd48d7cb..eeeae5b0cc36 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -15,6 +15,8 @@ #ifndef __AA_APPARMORFS_H #define __AA_APPARMORFS_H +extern struct path aa_null; + enum aa_fs_type { AA_FS_TYPE_BOOLEAN, AA_FS_TYPE_STRING, diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 820d86d266fe..89cffddd7e75 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -44,6 +44,7 @@ struct aa_ns_acct { * @sub_ns: list of namespaces under the current namespace. * @uniq_null: uniq value used for null learning profiles * @uniq_id: a unique id count for the profiles in the namespace + * @level: level of ns within the tree hierarchy * @dents: dentries for the namespaces file entries in apparmorfs * * An aa_ns defines the set profiles that are searched to determine which @@ -66,6 +67,7 @@ struct aa_ns { struct list_head sub_ns; atomic_t uniq_null; long uniq_id; + int level; struct dentry *dents[AAFS_NS_SIZEOF]; }; From ee2351e4b07cb7e3609f8661effe0382fb23646b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:46 -0800 Subject: [PATCH 0406/1587] apparmor: track ns level so it can be used to help in view checks Signed-off-by: John Johansen --- security/apparmor/policy_ns.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 1e19bd3c7851..93d1826c4b09 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -204,6 +204,7 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, return ERR_PTR(error); } ns->parent = aa_get_ns(parent); + ns->level = parent->level + 1; list_add_rcu(&ns->base.list, &parent->sub_ns); /* add list ref */ aa_get_ns(ns); From b79473f2de3eb3320e2a145da8a2ea03c7331784 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:47 -0800 Subject: [PATCH 0407/1587] apparmor: Make aa_remove_profile() callable from a different view This is prep work for fs operations being able to remove namespaces. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 3 ++- security/apparmor/include/policy.h | 2 +- security/apparmor/policy.c | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 2501a65fe7d3..14b96a44a3f5 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -180,7 +180,8 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, error = PTR_ERR(data); if (!IS_ERR(data)) { data[size] = 0; - error = aa_remove_profiles(data, size); + error = aa_remove_profiles(__aa_current_profile()->ns, data, + size); kvfree(data); } diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 3527e3f5a099..8fcfb3c78d21 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -187,7 +187,7 @@ struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, bool noreplace); -ssize_t aa_remove_profiles(char *name, size_t size); +ssize_t aa_remove_profiles(struct aa_ns *view, char *name, size_t size); void __aa_profile_list_release(struct list_head *head); #define PROF_ADD 1 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 046edecc4c8a..0314faeacccd 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -944,6 +944,7 @@ free: /** * aa_remove_profiles - remove profile(s) from the system + * @view: namespace the remove is being done from * @fqname: name of the profile or namespace to remove (NOT NULL) * @size: size of the name * @@ -954,9 +955,9 @@ free: * * Returns: size of data consume else error code if fails */ -ssize_t aa_remove_profiles(char *fqname, size_t size) +ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) { - struct aa_ns *root, *ns = NULL; + struct aa_ns *root = NULL, *ns = NULL; struct aa_profile *profile = NULL; const char *name = fqname, *info = NULL; ssize_t error = 0; @@ -967,7 +968,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) goto fail; } - root = aa_current_profile()->ns; + root = view; if (fqname[0] == ':') { char *ns_name; From 3e3e569539864d5812ecb03792dc183ebbf81476 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:48 -0800 Subject: [PATCH 0408/1587] apparmor: allow introspecting the policy namespace name Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 14b96a44a3f5..9fd7f73a4e86 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -356,6 +356,7 @@ static const struct file_operations aa_fs_seq_hash_fops = { .release = single_release, }; + static int aa_fs_seq_show_ns_level(struct seq_file *seq, void *v) { struct aa_ns *ns = aa_current_profile()->ns; @@ -378,6 +379,28 @@ static const struct file_operations aa_fs_ns_level = { .release = single_release, }; +static int aa_fs_seq_show_ns_name(struct seq_file *seq, void *v) +{ + struct aa_ns *ns = aa_current_profile()->ns; + + seq_printf(seq, "%s\n", ns->base.name); + + return 0; +} + +static int aa_fs_seq_open_ns_name(struct inode *inode, struct file *file) +{ + return single_open(file, aa_fs_seq_show_ns_name, inode->i_private); +} + +static const struct file_operations aa_fs_ns_name = { + .owner = THIS_MODULE, + .open = aa_fs_seq_open_ns_name, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /** fns to setup dynamic per profile/namespace files **/ void __aa_fs_profile_rmdir(struct aa_profile *profile) { @@ -852,6 +875,7 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = { AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level), + AA_FS_FILE_FOPS(".ns_name", 0640, &aa_fs_ns_name), AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops), AA_FS_DIR("features", aa_fs_entry_features), { } From a6f233003b1af70132619bca386dfae1862a45e8 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:49 -0800 Subject: [PATCH 0409/1587] apparmor: allow specifying the profile doing the management Signed-off-by: John Johansen --- security/apparmor/policy.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 0314faeacccd..0125de6061fd 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -582,6 +582,7 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace, /** * aa_audit_policy - Do auditing of policy changes + * @profile: profile to check if it can manage policy * @op: policy operation being performed * @gfp: memory allocation flags * @name: name of profile being manipulated (NOT NULL) @@ -590,8 +591,8 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace, * * Returns: the error to be returned after audit is done */ -static int audit_policy(int op, gfp_t gfp, const char *name, const char *info, - int error) +static int audit_policy(struct aa_profile *profile, int op, gfp_t gfp, + const char *name, const char *info, int error) { struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; @@ -602,7 +603,7 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info, aad.info = info; aad.error = error; - return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp, + return aa_audit(AUDIT_APPARMOR_STATUS, profile, gfp, &sa, NULL); } @@ -632,12 +633,14 @@ bool aa_may_manage_policy(int op) { /* check if loading policy is locked out */ if (aa_g_lock_policy) { - audit_policy(op, GFP_KERNEL, NULL, "policy_locked", -EACCES); + audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, + "policy_locked", -EACCES); return 0; } if (!policy_admin_capable()) { - audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES); + audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, + "not policy admin", -EACCES); return 0; } @@ -762,6 +765,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, /** * aa_replace_profiles - replace profile(s) on the profile list * @view: namespace load is viewed from + * @profile: profile that is attempting to load/replace policy * @udata: serialized data stream (NOT NULL) * @size: size of the serialized data stream * @noreplace: true if only doing addition, no replacement allowed @@ -790,7 +794,8 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, /* released below */ ns = aa_prepare_ns(view, ns_name); if (!ns) { - error = audit_policy(op, GFP_KERNEL, ns_name, + error = audit_policy(__aa_current_profile(), op, GFP_KERNEL, + ns_name, "failed to prepare namespace", -ENOMEM); goto free; } @@ -867,7 +872,8 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, list_del_init(&ent->list); op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(op, GFP_ATOMIC, ent->new->base.hname, NULL, error); + audit_policy(__aa_current_profile(), op, GFP_ATOMIC, + ent->new->base.hname, NULL, error); if (ent->old) { __replace_profile(ent->old, ent->new, 1); @@ -921,7 +927,8 @@ fail_lock: /* audit cause of failure */ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(op, GFP_KERNEL, ent->new->base.hname, info, error); + audit_policy(__aa_current_profile(), op, GFP_KERNEL, + ent->new->base.hname, info, error); /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; list_for_each_entry(tmp, &lh, list) { @@ -931,7 +938,8 @@ fail_lock: continue; } op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(op, GFP_KERNEL, tmp->new->base.hname, info, error); + audit_policy(__aa_current_profile(), op, GFP_KERNEL, + tmp->new->base.hname, info, error); } free: list_for_each_entry_safe(ent, tmp, &lh, list) { @@ -1004,7 +1012,8 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) } /* don't fail removal if audit fails */ - (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); + (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, + name, info, error); aa_put_ns(ns); aa_put_profile(profile); return size; @@ -1014,6 +1023,7 @@ fail_ns_lock: aa_put_ns(ns); fail: - (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); + (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, + name, info, error); return error; } From 2bd8dbbf22fe9eb2a99273436f815d49ceb23a8f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:50 -0800 Subject: [PATCH 0410/1587] apparmor: add ns being viewed as a param to policy_view_capable() Prepare for a tighter pairing of user namespaces and apparmor policy namespaces, by making the ns to be viewed available and checking that the user namespace level is the same as the policy ns level. This strict pairing will be relaxed once true support of user namespaces lands. Signed-off-by: John Johansen --- security/apparmor/include/context.h | 6 ++++++ security/apparmor/include/policy.h | 4 +++- security/apparmor/lsm.c | 8 ++++---- security/apparmor/policy.c | 25 ++++++++++++++++++++++--- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index a0acc2390fae..d378bff47ccd 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -20,6 +20,7 @@ #include #include "policy.h" +#include "policy_ns.h" #define cred_cxt(X) (X)->security #define current_cxt() cred_cxt(current_cred()) @@ -162,6 +163,11 @@ static inline struct aa_profile *aa_current_profile(void) return cxt->profile; } +static inline struct aa_ns *aa_get_current_ns(void) +{ + return aa_get_ns(__aa_current_profile()->ns); +} + /** * aa_clear_task_cxt_trans - clear transition tracking info from the cxt * @cxt: task context to clear (NOT NULL) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 8fcfb3c78d21..b0b65c525bcc 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -33,6 +33,8 @@ struct aa_ns; +extern int unprivileged_userns_apparmor_policy; + extern const char *const aa_profile_mode_names[]; #define APPARMOR_MODE_NAMES_MAX_INDEX 4 @@ -297,7 +299,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile) return profile->audit; } -bool policy_view_capable(void); +bool policy_view_capable(struct aa_ns *ns); bool policy_admin_capable(void); bool aa_may_manage_policy(int op); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f852cd626f2e..f83ba33651a0 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -745,7 +745,7 @@ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable()) + if (!policy_view_capable(NULL)) return -EPERM; return param_get_bool(buffer, kp); } @@ -759,7 +759,7 @@ static int param_set_aabool(const char *val, const struct kernel_param *kp) static int param_get_aabool(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable()) + if (!policy_view_capable(NULL)) return -EPERM; return param_get_bool(buffer, kp); } @@ -773,14 +773,14 @@ static int param_set_aauint(const char *val, const struct kernel_param *kp) static int param_get_aauint(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable()) + if (!policy_view_capable(NULL)) return -EPERM; return param_get_uint(buffer, kp); } static int param_get_audit(char *buffer, struct kernel_param *kp) { - if (!policy_view_capable()) + if (!policy_view_capable(NULL)) return -EPERM; if (!apparmor_enabled) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 0125de6061fd..f092c04c7c4e 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -76,6 +76,7 @@ #include #include #include +#include #include "include/apparmor.h" #include "include/capability.h" @@ -89,6 +90,7 @@ #include "include/policy_unpack.h" #include "include/resource.h" +int unprivileged_userns_apparmor_policy = 1; const char *const aa_profile_mode_names[] = { "enforce", @@ -607,20 +609,37 @@ static int audit_policy(struct aa_profile *profile, int op, gfp_t gfp, &sa, NULL); } -bool policy_view_capable(void) +/** + * policy_view_capable - check if viewing policy in at @ns is allowed + * ns: namespace being viewed by current task (may be NULL) + * Returns: true if viewing policy is allowed + * + * If @ns is NULL then the namespace being viewed is assumed to be the + * tasks current namespace. + */ +bool policy_view_capable(struct aa_ns *ns) { struct user_namespace *user_ns = current_user_ns(); + struct aa_ns *view_ns = aa_get_current_ns(); + bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) || + in_egroup_p(make_kgid(user_ns, 0)); bool response = false; + if (!ns) + ns = view_ns; - if (ns_capable(user_ns, CAP_MAC_ADMIN)) + if (root_in_user_ns && aa_ns_visible(view_ns, ns, true) && + (user_ns == &init_user_ns || + (unprivileged_userns_apparmor_policy != 0 && + user_ns->level == view_ns->level))) response = true; + aa_put_ns(view_ns); return response; } bool policy_admin_capable(void) { - return policy_view_capable() && !aa_g_lock_policy; + return policy_view_capable(NULL) && !aa_g_lock_policy; } /** From fd2a80438d736012129977bec779db093979057e Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:51 -0800 Subject: [PATCH 0411/1587] apparmor: add ns being viewed as a param to policy_admin_capable() Prepare for a tighter pairing of user namespaces and apparmor policy namespaces, by making the ns to be viewed available. Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 2 +- security/apparmor/lsm.c | 12 ++++++------ security/apparmor/policy.c | 12 +++++++++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index b0b65c525bcc..27f9171fa31f 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -300,7 +300,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile) } bool policy_view_capable(struct aa_ns *ns); -bool policy_admin_capable(void); +bool policy_admin_capable(struct aa_ns *ns); bool aa_may_manage_policy(int op); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f83ba33651a0..09f1c407c4d8 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -738,7 +738,7 @@ __setup("apparmor=", apparmor_enabled_setup); /* set global flag turning off the ability to load policy */ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; return param_set_bool(val, kp); } @@ -752,7 +752,7 @@ static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp) static int param_set_aabool(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; return param_set_bool(val, kp); } @@ -766,7 +766,7 @@ static int param_get_aabool(char *buffer, const struct kernel_param *kp) static int param_set_aauint(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; return param_set_uint(val, kp); } @@ -792,7 +792,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp) static int param_set_audit(const char *val, struct kernel_param *kp) { int i; - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; if (!apparmor_enabled) @@ -813,7 +813,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp) static int param_get_mode(char *buffer, struct kernel_param *kp) { - if (!policy_admin_capable()) + if (!policy_view_capable(NULL)) return -EPERM; if (!apparmor_enabled) @@ -825,7 +825,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) static int param_set_mode(const char *val, struct kernel_param *kp) { int i; - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; if (!apparmor_enabled) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index f092c04c7c4e..ef64c25b2a45 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -637,9 +637,15 @@ bool policy_view_capable(struct aa_ns *ns) return response; } -bool policy_admin_capable(void) +bool policy_admin_capable(struct aa_ns *ns) { - return policy_view_capable(NULL) && !aa_g_lock_policy; + struct user_namespace *user_ns = current_user_ns(); + bool capable = ns_capable(user_ns, CAP_MAC_ADMIN); + + AA_DEBUG("cap_mac_admin? %d\n", capable); + AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); + + return policy_view_capable(ns) && capable && !aa_g_lock_policy; } /** @@ -657,7 +663,7 @@ bool aa_may_manage_policy(int op) return 0; } - if (!policy_admin_capable()) { + if (!policy_admin_capable(NULL)) { audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, "not policy admin", -EACCES); return 0; From 078c73c63fb2878689da334f112507639c72c14f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:52 -0800 Subject: [PATCH 0412/1587] apparmor: add profile and ns params to aa_may_manage_policy() Policy management will be expanded beyond traditional unconfined root. This will require knowning the profile of the task doing the management and the ns view. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 2 +- security/apparmor/include/policy.h | 2 +- security/apparmor/policy.c | 22 ++++++++++------------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 9fd7f73a4e86..cc6ee1ee2b42 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -100,7 +100,7 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, * Don't allow profile load/replace/remove from profiles that don't * have CAP_MAC_ADMIN */ - if (!aa_may_manage_policy(op)) + if (!aa_may_manage_policy(__aa_current_profile(), NULL, op)) return ERR_PTR(-EACCES); /* freed by caller to simple_write_to_buffer */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 27f9171fa31f..95641e235d47 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -301,6 +301,6 @@ static inline int AUDIT_MODE(struct aa_profile *profile) bool policy_view_capable(struct aa_ns *ns); bool policy_admin_capable(struct aa_ns *ns); -bool aa_may_manage_policy(int op); +int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index ef64c25b2a45..27d93aa58016 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -650,26 +650,24 @@ bool policy_admin_capable(struct aa_ns *ns) /** * aa_may_manage_policy - can the current task manage policy + * @profile: profile to check if it can manage policy * @op: the policy manipulation operation being done * - * Returns: true if the task is allowed to manipulate policy + * Returns: 0 if the task is allowed to manipulate policy else error */ -bool aa_may_manage_policy(int op) +int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op) { /* check if loading policy is locked out */ - if (aa_g_lock_policy) { - audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, + if (aa_g_lock_policy) + return audit_policy(profile, op, GFP_KERNEL, NULL, "policy_locked", -EACCES); - return 0; - } - if (!policy_admin_capable(NULL)) { - audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, - "not policy admin", -EACCES); - return 0; - } + if (!policy_admin_capable(ns)) + return audit_policy(profile, op, GFP_KERNEL, NULL, + "not policy admin", -EACCES); - return 1; + /* TODO: add fine grained mediation of policy loads */ + return 0; } static struct aa_profile *__list_lookup_parent(struct list_head *lh, From fc1c9fd10a53a17abb3348adb2ec5d29813a0397 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:54 -0800 Subject: [PATCH 0413/1587] apparmor: add ns name to the audit data for policy loads Signed-off-by: John Johansen --- security/apparmor/include/audit.h | 1 + security/apparmor/policy.c | 34 ++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index ba3dfd17f23f..dbfb4a6d72b6 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -113,6 +113,7 @@ struct apparmor_audit_data { void *target; struct { long pos; + const char *ns; void *target; } iface; struct { diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 27d93aa58016..3c5c0b28eac5 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -582,11 +582,23 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace, return 0; } +/* audit callback for net specific fields */ +static void audit_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; + + if (sa->aad->iface.ns) { + audit_log_format(ab, " ns="); + audit_log_untrustedstring(ab, sa->aad->iface.ns); + } +} + /** * aa_audit_policy - Do auditing of policy changes * @profile: profile to check if it can manage policy * @op: policy operation being performed * @gfp: memory allocation flags + * @nsname: name of the ns being manipulated (MAY BE NULL) * @name: name of profile being manipulated (NOT NULL) * @info: any extra information to be audited (MAYBE NULL) * @error: error code @@ -594,19 +606,21 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace, * Returns: the error to be returned after audit is done */ static int audit_policy(struct aa_profile *profile, int op, gfp_t gfp, - const char *name, const char *info, int error) + const char *nsname, const char *name, + const char *info, int error) { struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; sa.type = LSM_AUDIT_DATA_NONE; sa.aad = &aad; aad.op = op; + aad.iface.ns = nsname; aad.name = name; aad.info = info; aad.error = error; return aa_audit(AUDIT_APPARMOR_STATUS, profile, gfp, - &sa, NULL); + &sa, audit_cb); } /** @@ -659,11 +673,11 @@ int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op) { /* check if loading policy is locked out */ if (aa_g_lock_policy) - return audit_policy(profile, op, GFP_KERNEL, NULL, + return audit_policy(profile, op, GFP_KERNEL, NULL, NULL, "policy_locked", -EACCES); if (!policy_admin_capable(ns)) - return audit_policy(profile, op, GFP_KERNEL, NULL, + return audit_policy(profile, op, GFP_KERNEL, NULL, NULL, "not policy admin", -EACCES); /* TODO: add fine grained mediation of policy loads */ @@ -818,7 +832,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, ns = aa_prepare_ns(view, ns_name); if (!ns) { error = audit_policy(__aa_current_profile(), op, GFP_KERNEL, - ns_name, + NULL, ns_name, "failed to prepare namespace", -ENOMEM); goto free; } @@ -895,7 +909,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, list_del_init(&ent->list); op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_ATOMIC, + audit_policy(__aa_current_profile(), op, GFP_ATOMIC, NULL, ent->new->base.hname, NULL, error); if (ent->old) { @@ -950,7 +964,7 @@ fail_lock: /* audit cause of failure */ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_KERNEL, + audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, ent->new->base.hname, info, error); /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; @@ -961,7 +975,7 @@ fail_lock: continue; } op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_KERNEL, + audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, tmp->new->base.hname, info, error); } free: @@ -1036,7 +1050,7 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) /* don't fail removal if audit fails */ (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, - name, info, error); + NULL, name, info, error); aa_put_ns(ns); aa_put_profile(profile); return size; @@ -1047,6 +1061,6 @@ fail_ns_lock: fail: (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, - name, info, error); + NULL, name, info, error); return error; } From 5ac8c355ae0013d82b3a07b49aebeadfce9b6e52 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:55 -0800 Subject: [PATCH 0414/1587] apparmor: allow introspecting the loaded policy pre internal transform Store loaded policy and allow introspecting it through apparmorfs. This has several uses from debugging, policy validation, and policy checkpoint and restore for containers. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 217 +++++++++++++++++----- security/apparmor/crypto.c | 39 +++- security/apparmor/include/apparmorfs.h | 5 + security/apparmor/include/crypto.h | 5 + security/apparmor/include/policy.h | 5 +- security/apparmor/include/policy_unpack.h | 27 ++- security/apparmor/policy.c | 14 +- security/apparmor/policy_unpack.c | 28 ++- 8 files changed, 280 insertions(+), 60 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index cc6ee1ee2b42..2e6790cf54da 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -33,6 +33,7 @@ #include "include/policy.h" #include "include/policy_ns.h" #include "include/resource.h" +#include "include/policy_unpack.h" /** * aa_mangle_name - mangle a profile name to std profile layout form @@ -84,11 +85,13 @@ static int mangle_name(const char *name, char *target) * Returns: kernel buffer containing copy of user buffer data or an * ERR_PTR on failure. */ -static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, - size_t alloc_size, size_t copy_size, - loff_t *pos) +static struct aa_loaddata *aa_simple_write_to_buffer(int op, + const char __user *userbuf, + size_t alloc_size, + size_t copy_size, + loff_t *pos) { - char *data; + struct aa_loaddata *data; BUG_ON(copy_size > alloc_size); @@ -96,19 +99,16 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, /* only writes from pos 0, that is complete writes */ return ERR_PTR(-ESPIPE); - /* - * Don't allow profile load/replace/remove from profiles that don't - * have CAP_MAC_ADMIN - */ - if (!aa_may_manage_policy(__aa_current_profile(), NULL, op)) - return ERR_PTR(-EACCES); - /* freed by caller to simple_write_to_buffer */ - data = kvmalloc(alloc_size); + data = kvmalloc(sizeof(*data) + alloc_size); if (data == NULL) return ERR_PTR(-ENOMEM); + kref_init(&data->count); + data->size = copy_size; + data->hash = NULL; + data->abi = 0; - if (copy_from_user(data, userbuf, copy_size)) { + if (copy_from_user(data->data, userbuf, copy_size)) { kvfree(data); return ERR_PTR(-EFAULT); } @@ -116,22 +116,34 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, return data; } +static ssize_t policy_update(int binop, const char __user *buf, size_t size, + loff_t *pos) +{ + ssize_t error; + struct aa_loaddata *data; + struct aa_profile *profile = aa_current_profile(); + int op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL; + /* high level check about policy management - fine grained in + * below after unpack + */ + error = aa_may_manage_policy(profile, profile->ns, op); + if (error) + return error; + + data = aa_simple_write_to_buffer(op, buf, size, size, pos); + error = PTR_ERR(data); + if (!IS_ERR(data)) { + error = aa_replace_profiles(profile->ns, binop, data); + aa_put_loaddata(data); + } + + return error; +} -/* .load file hook fn to load policy */ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - char *data; - ssize_t error; - - data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos); - - error = PTR_ERR(data); - if (!IS_ERR(data)) { - error = aa_replace_profiles(__aa_current_profile()->ns, data, - size, PROF_ADD); - kvfree(data); - } + int error = policy_update(PROF_ADD, buf, size, pos); return error; } @@ -145,16 +157,7 @@ static const struct file_operations aa_fs_profile_load = { static ssize_t profile_replace(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - char *data; - ssize_t error; - - data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos); - error = PTR_ERR(data); - if (!IS_ERR(data)) { - error = aa_replace_profiles(__aa_current_profile()->ns, data, - size, PROF_REPLACE); - kvfree(data); - } + int error = policy_update(PROF_REPLACE, buf, size, pos); return error; } @@ -164,27 +167,35 @@ static const struct file_operations aa_fs_profile_replace = { .llseek = default_llseek, }; -/* .remove file hook fn to remove loaded policy */ static ssize_t profile_remove(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - char *data; + struct aa_loaddata *data; + struct aa_profile *profile; ssize_t error; + profile = aa_current_profile(); + /* high level check about policy management - fine grained in + * below after unpack + */ + error = aa_may_manage_policy(profile, profile->ns, OP_PROF_RM); + if (error) + goto out; + /* * aa_remove_profile needs a null terminated string so 1 extra * byte is allocated and the copied data is null terminated. */ - data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos); + data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, + pos); error = PTR_ERR(data); if (!IS_ERR(data)) { - data[size] = 0; - error = aa_remove_profiles(__aa_current_profile()->ns, data, - size); - kvfree(data); + data->data[size] = 0; + error = aa_remove_profiles(profile->ns, data->data, size); + aa_put_loaddata(data); } - + out: return error; } @@ -401,6 +412,100 @@ static const struct file_operations aa_fs_ns_name = { .release = single_release, }; +static int rawdata_release(struct inode *inode, struct file *file) +{ + /* TODO: switch to loaddata when profile switched to symlink */ + aa_put_loaddata(file->private_data); + + return 0; +} + +static int aa_fs_seq_raw_abi_show(struct seq_file *seq, void *v) +{ + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); + + if (profile->rawdata->abi) { + seq_printf(seq, "v%d", profile->rawdata->abi); + seq_puts(seq, "\n"); + } + aa_put_profile(profile); + + return 0; +} + +static int aa_fs_seq_raw_abi_open(struct inode *inode, struct file *file) +{ + return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_abi_show); +} + +static const struct file_operations aa_fs_seq_raw_abi_fops = { + .owner = THIS_MODULE, + .open = aa_fs_seq_raw_abi_open, + .read = seq_read, + .llseek = seq_lseek, + .release = aa_fs_seq_profile_release, +}; + +static int aa_fs_seq_raw_hash_show(struct seq_file *seq, void *v) +{ + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); + unsigned int i, size = aa_hash_size(); + + if (profile->rawdata->hash) { + for (i = 0; i < size; i++) + seq_printf(seq, "%.2x", profile->rawdata->hash[i]); + seq_puts(seq, "\n"); + } + aa_put_profile(profile); + + return 0; +} + +static int aa_fs_seq_raw_hash_open(struct inode *inode, struct file *file) +{ + return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_hash_show); +} + +static const struct file_operations aa_fs_seq_raw_hash_fops = { + .owner = THIS_MODULE, + .open = aa_fs_seq_raw_hash_open, + .read = seq_read, + .llseek = seq_lseek, + .release = aa_fs_seq_profile_release, +}; + +static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size, + loff_t *ppos) +{ + struct aa_loaddata *rawdata = file->private_data; + + return simple_read_from_buffer(buf, size, ppos, rawdata->data, + rawdata->size); +} + +static int rawdata_open(struct inode *inode, struct file *file) +{ + struct aa_proxy *proxy = inode->i_private; + struct aa_profile *profile; + + if (!policy_view_capable(NULL)) + return -EACCES; + profile = aa_get_profile_rcu(&proxy->profile); + file->private_data = aa_get_loaddata(profile->rawdata); + aa_put_profile(profile); + + return 0; +} + +static const struct file_operations aa_fs_rawdata_fops = { + .open = rawdata_open, + .read = rawdata_read, + .llseek = generic_file_llseek, + .release = rawdata_release, +}; + /** fns to setup dynamic per profile/namespace files **/ void __aa_fs_profile_rmdir(struct aa_profile *profile) { @@ -512,6 +617,29 @@ int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) profile->dents[AAFS_PROF_HASH] = dent; } + if (profile->rawdata) { + dent = create_profile_file(dir, "raw_sha1", profile, + &aa_fs_seq_raw_hash_fops); + if (IS_ERR(dent)) + goto fail; + profile->dents[AAFS_PROF_RAW_HASH] = dent; + + dent = create_profile_file(dir, "raw_abi", profile, + &aa_fs_seq_raw_abi_fops); + if (IS_ERR(dent)) + goto fail; + profile->dents[AAFS_PROF_RAW_ABI] = dent; + + dent = securityfs_create_file("raw_data", S_IFREG | 0444, dir, + profile->proxy, + &aa_fs_rawdata_fops); + if (IS_ERR(dent)) + goto fail; + profile->dents[AAFS_PROF_RAW_DATA] = dent; + d_inode(dent)->i_size = profile->rawdata->size; + aa_get_proxy(profile->proxy); + } + list_for_each_entry(child, &profile->base.profiles, base.list) { error = __aa_fs_profile_mkdir(child, prof_child_dir(profile)); if (error) @@ -817,6 +945,9 @@ static const struct seq_operations aa_fs_profiles_op = { static int profiles_open(struct inode *inode, struct file *file) { + if (!policy_view_capable(NULL)) + return -EACCES; + return seq_open(file, &aa_fs_profiles_op); } diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c index b75dab0df1cb..de8dc78b6144 100644 --- a/security/apparmor/crypto.c +++ b/security/apparmor/crypto.c @@ -29,6 +29,43 @@ unsigned int aa_hash_size(void) return apparmor_hash_size; } +char *aa_calc_hash(void *data, size_t len) +{ + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(apparmor_tfm)]; + } desc; + char *hash = NULL; + int error = -ENOMEM; + + if (!apparmor_tfm) + return NULL; + + hash = kzalloc(apparmor_hash_size, GFP_KERNEL); + if (!hash) + goto fail; + + desc.shash.tfm = apparmor_tfm; + desc.shash.flags = 0; + + error = crypto_shash_init(&desc.shash); + if (error) + goto fail; + error = crypto_shash_update(&desc.shash, (u8 *) data, len); + if (error) + goto fail; + error = crypto_shash_final(&desc.shash, hash); + if (error) + goto fail; + + return hash; + +fail: + kfree(hash); + + return ERR_PTR(error); +} + int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, size_t len) { @@ -37,7 +74,7 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, char ctx[crypto_shash_descsize(apparmor_tfm)]; } desc; int error = -ENOMEM; - u32 le32_version = cpu_to_le32(version); + __le32 le32_version = cpu_to_le32(version); if (!aa_g_hash_policy) return 0; diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index eeeae5b0cc36..a593e75b3b03 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -70,6 +70,7 @@ enum aafs_ns_type { AAFS_NS_DIR, AAFS_NS_PROFS, AAFS_NS_NS, + AAFS_NS_RAW_DATA, AAFS_NS_COUNT, AAFS_NS_MAX_COUNT, AAFS_NS_SIZE, @@ -85,12 +86,16 @@ enum aafs_prof_type { AAFS_PROF_MODE, AAFS_PROF_ATTACH, AAFS_PROF_HASH, + AAFS_PROF_RAW_DATA, + AAFS_PROF_RAW_HASH, + AAFS_PROF_RAW_ABI, AAFS_PROF_SIZEOF, }; #define ns_dir(X) ((X)->dents[AAFS_NS_DIR]) #define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS]) #define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS]) +#define ns_subdata_dir(X) ((X)->dents[AAFS_NS_RAW_DATA]) #define prof_dir(X) ((X)->dents[AAFS_PROF_DIR]) #define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS]) diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h index dc418e5024d9..c1469f8db174 100644 --- a/security/apparmor/include/crypto.h +++ b/security/apparmor/include/crypto.h @@ -18,9 +18,14 @@ #ifdef CONFIG_SECURITY_APPARMOR_HASH unsigned int aa_hash_size(void); +char *aa_calc_hash(void *data, size_t len); int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, size_t len); #else +static inline char *aa_calc_hash(void *data, size_t len) +{ + return NULL; +} static inline int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, size_t len) { diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 95641e235d47..fbbc8677f527 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -161,6 +161,7 @@ struct aa_profile { struct aa_caps caps; struct aa_rlimit rlimits; + struct aa_loaddata *rawdata; unsigned char *hash; char *dirname; struct dentry *dents[AAFS_PROF_SIZEOF]; @@ -187,8 +188,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, const char *fqname, size_t n); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); -ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, - bool noreplace); +ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, + struct aa_loaddata *udata); ssize_t aa_remove_profiles(struct aa_ns *view, char *name, size_t size); void __aa_profile_list_release(struct list_head *head); diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h index c214fb88b1bc..7b675b6f7f02 100644 --- a/security/apparmor/include/policy_unpack.h +++ b/security/apparmor/include/policy_unpack.h @@ -16,6 +16,7 @@ #define __POLICY_INTERFACE_H #include +#include struct aa_load_ent { struct list_head list; @@ -34,6 +35,30 @@ struct aa_load_ent *aa_load_ent_alloc(void); #define PACKED_MODE_KILL 2 #define PACKED_MODE_UNCONFINED 3 -int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns); +/* struct aa_loaddata - buffer of policy load data set */ +struct aa_loaddata { + struct kref count; + size_t size; + int abi; + unsigned char *hash; + char data[]; +}; + +int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns); + +static inline struct aa_loaddata * +aa_get_loaddata(struct aa_loaddata *data) +{ + if (data) + kref_get(&(data->count)); + return data; +} + +void aa_loaddata_kref(struct kref *kref); +static inline void aa_put_loaddata(struct aa_loaddata *data) +{ + if (data) + kref_put(&data->count, aa_loaddata_kref); +} #endif /* __POLICY_INTERFACE_H */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 3c5c0b28eac5..ff29b606f2b3 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -228,6 +228,7 @@ void aa_free_profile(struct aa_profile *profile) aa_put_proxy(profile->proxy); kzfree(profile->hash); + aa_put_loaddata(profile->rawdata); kzfree(profile); } @@ -802,10 +803,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, /** * aa_replace_profiles - replace profile(s) on the profile list * @view: namespace load is viewed from - * @profile: profile that is attempting to load/replace policy - * @udata: serialized data stream (NOT NULL) - * @size: size of the serialized data stream * @noreplace: true if only doing addition, no replacement allowed + * @udata: serialized data stream (NOT NULL) * * unpack and replace a profile on the profile list and uses of that profile * by any aa_task_cxt. If the profile does not exist on the profile list @@ -813,8 +812,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, * * Returns: size of data consumed else error code on failure. */ -ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, - bool noreplace) +ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, + struct aa_loaddata *udata) { const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; @@ -824,7 +823,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, LIST_HEAD(lh); /* released below */ - error = aa_unpack(udata, size, &lh, &ns_name); + error = aa_unpack(udata, &lh, &ns_name); if (error) goto out; @@ -841,6 +840,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, /* setup parent and ns info */ list_for_each_entry(ent, &lh, list) { struct aa_policy *policy; + ent->new->rawdata = aa_get_loaddata(udata); error = __lookup_replace(ns, ent->new->base.hname, noreplace, &ent->old, &info); if (error) @@ -957,7 +957,7 @@ out: if (error) return error; - return size; + return udata->size; fail_lock: mutex_unlock(&ns->lock); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 51a7f9fc8a3e..fb4ef84b88e1 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -117,6 +117,16 @@ static int audit_iface(struct aa_profile *new, const char *name, audit_cb); } +void aa_loaddata_kref(struct kref *kref) +{ + struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count); + + if (d) { + kzfree(d->hash); + kvfree(d); + } +} + /* test if read will be in packed data bounds */ static bool inbounds(struct aa_ext *e, size_t size) { @@ -749,7 +759,6 @@ struct aa_load_ent *aa_load_ent_alloc(void) /** * aa_unpack - unpack packed binary profile(s) data loaded from user space * @udata: user data copied to kmem (NOT NULL) - * @size: the size of the user data * @lh: list to place unpacked profiles in a aa_repl_ws * @ns: Returns namespace profile is in if specified else NULL (NOT NULL) * @@ -759,15 +768,16 @@ struct aa_load_ent *aa_load_ent_alloc(void) * * Returns: profile(s) on @lh else error pointer if fails to unpack */ -int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) +int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, + const char **ns) { struct aa_load_ent *tmp, *ent; struct aa_profile *profile = NULL; int error; struct aa_ext e = { - .start = udata, - .end = udata + size, - .pos = udata, + .start = udata->data, + .end = udata->data + udata->size, + .pos = udata->data, }; *ns = NULL; @@ -802,7 +812,13 @@ int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) ent->new = profile; list_add_tail(&ent->list, lh); } - + udata->abi = e.version & K_ABI_MASK; + udata->hash = aa_calc_hash(udata->data, udata->size); + if (IS_ERR(udata->hash)) { + error = PTR_ERR(udata->hash); + udata->hash = NULL; + goto fail; + } return 0; fail_profile: From 04dc715e24d0820bf8740e1a1135ed61fe162bc8 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:56 -0800 Subject: [PATCH 0415/1587] apparmor: audit policy ns specified in policy load Verify that profiles in a load set specify the same policy ns and audit the name of the policy ns that policy is being loaded for. Signed-off-by: John Johansen --- security/apparmor/include/policy_unpack.h | 1 + security/apparmor/policy.c | 54 +++++++++++++++++------ security/apparmor/policy_unpack.c | 46 ++++++++++++++----- 3 files changed, 77 insertions(+), 24 deletions(-) diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h index 7b675b6f7f02..4c1319eebc42 100644 --- a/security/apparmor/include/policy_unpack.h +++ b/security/apparmor/include/policy_unpack.h @@ -23,6 +23,7 @@ struct aa_load_ent { struct aa_profile *new; struct aa_profile *old; struct aa_profile *rename; + const char *ns_name; }; void aa_load_ent_free(struct aa_load_ent *ent); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index ff29b606f2b3..eb1ccd171789 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -819,7 +819,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, struct aa_ns *ns = NULL; struct aa_load_ent *ent, *tmp; int op = OP_PROF_REPL; - ssize_t error; + ssize_t count, error; LIST_HEAD(lh); /* released below */ @@ -827,14 +827,40 @@ ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, if (error) goto out; - /* released below */ - ns = aa_prepare_ns(view, ns_name); - if (!ns) { - error = audit_policy(__aa_current_profile(), op, GFP_KERNEL, - NULL, ns_name, - "failed to prepare namespace", -ENOMEM); - goto free; + /* ensure that profiles are all for the same ns + * TODO: update locking to remove this constaint. All profiles in + * the load set must succeed as a set or the load will + * fail. Sort ent list and take ns locks in hierarchy order + */ + count = 0; + list_for_each_entry(ent, &lh, list) { + if (ns_name) { + if (ent->ns_name && + strcmp(ent->ns_name, ns_name) != 0) { + info = "policy load has mixed namespaces"; + error = -EACCES; + goto fail; + } + } else if (ent->ns_name) { + if (count) { + info = "policy load has mixed namespaces"; + error = -EACCES; + goto fail; + } + ns_name = ent->ns_name; + } else + count++; } + if (ns_name) { + ns = aa_prepare_ns(view, ns_name); + if (IS_ERR(ns)) { + info = "failed to prepare namespace"; + error = PTR_ERR(ns); + ns = NULL; + goto fail; + } + } else + ns = aa_get_ns(view); mutex_lock(&ns->lock); /* setup parent and ns info */ @@ -964,7 +990,8 @@ fail_lock: /* audit cause of failure */ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, +fail: + audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name, ent->new->base.hname, info, error); /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; @@ -975,10 +1002,9 @@ fail_lock: continue; } op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, + audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name, tmp->new->base.hname, info, error); } -free: list_for_each_entry_safe(ent, tmp, &lh, list) { list_del_init(&ent->list); aa_load_ent_free(ent); @@ -1005,6 +1031,7 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) struct aa_ns *root = NULL, *ns = NULL; struct aa_profile *profile = NULL; const char *name = fqname, *info = NULL; + char *ns_name = NULL; ssize_t error = 0; if (*fqname == 0) { @@ -1016,7 +1043,6 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) root = view; if (fqname[0] == ':') { - char *ns_name; name = aa_split_fqname(fqname, &ns_name); /* released below */ ns = aa_find_ns(root, ns_name); @@ -1050,7 +1076,7 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) /* don't fail removal if audit fails */ (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, - NULL, name, info, error); + ns_name, name, info, error); aa_put_ns(ns); aa_put_profile(profile); return size; @@ -1061,6 +1087,6 @@ fail_ns_lock: fail: (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, - NULL, name, info, error); + ns_name, name, info, error); return error; } diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index fb4ef84b88e1..38c148f33fa4 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -91,6 +91,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) /** * audit_iface - do audit message for policy unpacking/load/replace/remove * @new: profile if it has been allocated (MAYBE NULL) + * @ns_name: name of the ns the profile is to be loaded to (MAY BE NULL) * @name: name of the profile being manipulated (MAYBE NULL) * @info: any extra info about the failure (MAYBE NULL) * @e: buffer position info @@ -98,14 +99,16 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: %0 or error */ -static int audit_iface(struct aa_profile *new, const char *name, - const char *info, struct aa_ext *e, int error) +static int audit_iface(struct aa_profile *new, const char *ns_name, + const char *name, const char *info, struct aa_ext *e, + int error) { struct aa_profile *profile = __aa_current_profile(); struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; sa.type = LSM_AUDIT_DATA_NONE; sa.aad = &aad; + aad.iface.ns = ns_name; if (e) aad.iface.pos = e->pos - e->start; aad.iface.target = new; @@ -486,19 +489,32 @@ fail: * * NOTE: unpack profile sets audit struct if there is a failure */ -static struct aa_profile *unpack_profile(struct aa_ext *e) +static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) { struct aa_profile *profile = NULL; - const char *name = NULL; + const char *tmpname, *tmpns = NULL, *name = NULL; + size_t ns_len; int i, error = -EPROTO; kernel_cap_t tmpcap; u32 tmp; + *ns_name = NULL; + /* check that we have the right struct being passed */ if (!unpack_nameX(e, AA_STRUCT, "profile")) goto fail; if (!unpack_str(e, &name, NULL)) goto fail; + if (*name == '\0') + goto fail; + + tmpname = aa_splitn_fqname(name, strlen(name), &tmpns, &ns_len); + if (tmpns) { + *ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL); + if (!*ns_name) + goto fail; + name = tmpname; + } profile = aa_alloc_profile(name, GFP_KERNEL); if (!profile) @@ -646,7 +662,8 @@ fail: name = NULL; else if (!name) name = "unknown"; - audit_iface(profile, name, "failed to unpack profile", e, error); + audit_iface(profile, NULL, name, "failed to unpack profile", e, + error); aa_free_profile(profile); return ERR_PTR(error); @@ -669,7 +686,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns) /* get the interface version */ if (!unpack_u32(e, &e->version, "version")) { if (required) { - audit_iface(NULL, NULL, "invalid profile format", + audit_iface(NULL, NULL, NULL, "invalid profile format", e, error); return error; } @@ -680,15 +697,21 @@ static int verify_header(struct aa_ext *e, int required, const char **ns) * Mask off everything that is not kernel abi version */ if (VERSION_LT(e->version, v5) && VERSION_GT(e->version, v7)) { - audit_iface(NULL, NULL, "unsupported interface version", + audit_iface(NULL, NULL, NULL, "unsupported interface version", e, error); return error; } /* read the namespace if present */ if (unpack_str(e, &name, "namespace")) { + if (*name == '\0') { + audit_iface(NULL, NULL, NULL, "invalid namespace name", + e, error); + return error; + } if (*ns && strcmp(*ns, name)) - audit_iface(NULL, NULL, "invalid ns change", e, error); + audit_iface(NULL, NULL, NULL, "invalid ns change", e, + error); else if (!*ns) *ns = name; } @@ -730,7 +753,7 @@ static int verify_profile(struct aa_profile *profile) if (profile->file.dfa && !verify_dfa_xindex(profile->file.dfa, profile->file.trans.size)) { - audit_iface(profile, NULL, "Invalid named transition", + audit_iface(profile, NULL, NULL, "Invalid named transition", NULL, -EPROTO); return -EPROTO; } @@ -744,6 +767,7 @@ void aa_load_ent_free(struct aa_load_ent *ent) aa_put_profile(ent->rename); aa_put_profile(ent->old); aa_put_profile(ent->new); + kfree(ent->ns_name); kzfree(ent); } } @@ -782,13 +806,14 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, *ns = NULL; while (e.pos < e.end) { + char *ns_name = NULL; void *start; error = verify_header(&e, e.pos == e.start, ns); if (error) goto fail; start = e.pos; - profile = unpack_profile(&e); + profile = unpack_profile(&e, &ns_name); if (IS_ERR(profile)) { error = PTR_ERR(profile); goto fail; @@ -810,6 +835,7 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, } ent->new = profile; + ent->ns_name = ns_name; list_add_tail(&ent->list, lh); } udata->abi = e.version & K_ABI_MASK; From 12dd7171d645a6658326ba234e6d4fc57a73bf98 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:57 -0800 Subject: [PATCH 0416/1587] apparmor: pass the subject profile into profile replace/remove This is just setup for new ns specific .load, .replace, .remove interface files. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 5 +++-- security/apparmor/include/policy.h | 7 ++++--- security/apparmor/policy.c | 25 ++++++++++++++----------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 2e6790cf54da..d654aacd7db4 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -133,7 +133,7 @@ static ssize_t policy_update(int binop, const char __user *buf, size_t size, data = aa_simple_write_to_buffer(op, buf, size, size, pos); error = PTR_ERR(data); if (!IS_ERR(data)) { - error = aa_replace_profiles(profile->ns, binop, data); + error = aa_replace_profiles(profile->ns, profile, binop, data); aa_put_loaddata(data); } @@ -192,7 +192,8 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, error = PTR_ERR(data); if (!IS_ERR(data)) { data->data[size] = 0; - error = aa_remove_profiles(profile->ns, data->data, size); + error = aa_remove_profiles(profile->ns, profile, data->data, + size); aa_put_loaddata(data); } out: diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index fbbc8677f527..b315ad5bdd85 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -188,9 +188,10 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, const char *fqname, size_t n); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); -ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, - struct aa_loaddata *udata); -ssize_t aa_remove_profiles(struct aa_ns *view, char *name, size_t size); +ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, + bool noreplace, struct aa_loaddata *udata); +ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile, + char *name, size_t size); void __aa_profile_list_release(struct list_head *head); #define PROF_ADD 1 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index eb1ccd171789..912cdbed7977 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -803,6 +803,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, /** * aa_replace_profiles - replace profile(s) on the profile list * @view: namespace load is viewed from + * @label: label that is attempting to load/replace policy * @noreplace: true if only doing addition, no replacement allowed * @udata: serialized data stream (NOT NULL) * @@ -812,8 +813,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, * * Returns: size of data consumed else error code on failure. */ -ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, - struct aa_loaddata *udata) +ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, + bool noreplace, struct aa_loaddata *udata) { const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; @@ -935,7 +936,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, list_del_init(&ent->list); op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_ATOMIC, NULL, + audit_policy(profile, op, GFP_ATOMIC, NULL, ent->new->base.hname, NULL, error); if (ent->old) { @@ -991,8 +992,8 @@ fail_lock: /* audit cause of failure */ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; fail: - audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name, - ent->new->base.hname, info, error); + audit_policy(profile, op, GFP_KERNEL, ns_name, ent->new->base.hname, + info, error); /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; list_for_each_entry(tmp, &lh, list) { @@ -1002,7 +1003,7 @@ fail: continue; } op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name, + audit_policy(profile, op, GFP_KERNEL, ns_name, tmp->new->base.hname, info, error); } list_for_each_entry_safe(ent, tmp, &lh, list) { @@ -1016,6 +1017,7 @@ fail: /** * aa_remove_profiles - remove profile(s) from the system * @view: namespace the remove is being done from + * @subj: profile attempting to remove policy * @fqname: name of the profile or namespace to remove (NOT NULL) * @size: size of the name * @@ -1026,7 +1028,8 @@ fail: * * Returns: size of data consume else error code if fails */ -ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) +ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj, + char *fqname, size_t size) { struct aa_ns *root = NULL, *ns = NULL; struct aa_profile *profile = NULL; @@ -1075,8 +1078,8 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) } /* don't fail removal if audit fails */ - (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, - ns_name, name, info, error); + (void) audit_policy(subj, OP_PROF_RM, GFP_KERNEL, ns_name, name, info, + error); aa_put_ns(ns); aa_put_profile(profile); return size; @@ -1086,7 +1089,7 @@ fail_ns_lock: aa_put_ns(ns); fail: - (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, - ns_name, name, info, error); + (void) audit_policy(subj, OP_PROF_RM, GFP_KERNEL, ns_name, name, info, + error); return error; } From b7fd2c0340eacbee892425e9007647568b7f2a3c Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:58 -0800 Subject: [PATCH 0417/1587] apparmor: add per policy ns .load, .replace, .remove interface files Having per policy ns interface files helps with containers restoring policy. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 146 +++++++++++++++++++++---- security/apparmor/include/apparmorfs.h | 6 + 2 files changed, 130 insertions(+), 22 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index d654aacd7db4..af36af88c4ed 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -117,7 +117,7 @@ static struct aa_loaddata *aa_simple_write_to_buffer(int op, } static ssize_t policy_update(int binop, const char __user *buf, size_t size, - loff_t *pos) + loff_t *pos, struct aa_ns *ns) { ssize_t error; struct aa_loaddata *data; @@ -126,24 +126,29 @@ static ssize_t policy_update(int binop, const char __user *buf, size_t size, /* high level check about policy management - fine grained in * below after unpack */ - error = aa_may_manage_policy(profile, profile->ns, op); + error = aa_may_manage_policy(profile, ns, op); if (error) return error; data = aa_simple_write_to_buffer(op, buf, size, size, pos); error = PTR_ERR(data); if (!IS_ERR(data)) { - error = aa_replace_profiles(profile->ns, profile, binop, data); + error = aa_replace_profiles(ns ? ns : profile->ns, profile, + binop, data); aa_put_loaddata(data); } return error; } +/* .load file hook fn to load policy */ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - int error = policy_update(PROF_ADD, buf, size, pos); + struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); + int error = policy_update(PROF_ADD, buf, size, pos, ns); + + aa_put_ns(ns); return error; } @@ -157,7 +162,10 @@ static const struct file_operations aa_fs_profile_load = { static ssize_t profile_replace(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - int error = policy_update(PROF_REPLACE, buf, size, pos); + struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); + int error = policy_update(PROF_REPLACE, buf, size, pos, ns); + + aa_put_ns(ns); return error; } @@ -167,18 +175,20 @@ static const struct file_operations aa_fs_profile_replace = { .llseek = default_llseek, }; +/* .remove file hook fn to remove loaded policy */ static ssize_t profile_remove(struct file *f, const char __user *buf, size_t size, loff_t *pos) { struct aa_loaddata *data; struct aa_profile *profile; ssize_t error; + struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); profile = aa_current_profile(); /* high level check about policy management - fine grained in * below after unpack */ - error = aa_may_manage_policy(profile, profile->ns, OP_PROF_RM); + error = aa_may_manage_policy(profile, ns, OP_PROF_RM); if (error) goto out; @@ -192,11 +202,12 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, error = PTR_ERR(data); if (!IS_ERR(data)) { data->data[size] = 0; - error = aa_remove_profiles(profile->ns, profile, data->data, - size); + error = aa_remove_profiles(ns ? ns : profile->ns, profile, + data->data, size); aa_put_loaddata(data); } out: + aa_put_ns(ns); return error; } @@ -676,12 +687,77 @@ void __aa_fs_ns_rmdir(struct aa_ns *ns) mutex_unlock(&sub->lock); } + if (ns_subns_dir(ns)) { + sub = d_inode(ns_subns_dir(ns))->i_private; + aa_put_ns(sub); + } + if (ns_subload(ns)) { + sub = d_inode(ns_subload(ns))->i_private; + aa_put_ns(sub); + } + if (ns_subreplace(ns)) { + sub = d_inode(ns_subreplace(ns))->i_private; + aa_put_ns(sub); + } + if (ns_subremove(ns)) { + sub = d_inode(ns_subremove(ns))->i_private; + aa_put_ns(sub); + } + for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) { securityfs_remove(ns->dents[i]); ns->dents[i] = NULL; } } +/* assumes cleanup in caller */ +static int __aa_fs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir) +{ + struct dentry *dent; + + AA_BUG(!ns); + AA_BUG(!dir); + + dent = securityfs_create_dir("profiles", dir); + if (IS_ERR(dent)) + return PTR_ERR(dent); + ns_subprofs_dir(ns) = dent; + + dent = securityfs_create_dir("raw_data", dir); + if (IS_ERR(dent)) + return PTR_ERR(dent); + ns_subdata_dir(ns) = dent; + + dent = securityfs_create_file(".load", 0640, dir, ns, + &aa_fs_profile_load); + if (IS_ERR(dent)) + return PTR_ERR(dent); + aa_get_ns(ns); + ns_subload(ns) = dent; + + dent = securityfs_create_file(".replace", 0640, dir, ns, + &aa_fs_profile_replace); + if (IS_ERR(dent)) + return PTR_ERR(dent); + aa_get_ns(ns); + ns_subreplace(ns) = dent; + + dent = securityfs_create_file(".remove", 0640, dir, ns, + &aa_fs_profile_remove); + if (IS_ERR(dent)) + return PTR_ERR(dent); + aa_get_ns(ns); + ns_subremove(ns) = dent; + + dent = securityfs_create_dir("namespaces", dir); + if (IS_ERR(dent)) + return PTR_ERR(dent); + aa_get_ns(ns); + ns_subns_dir(ns) = dent; + + return 0; +} + int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name) { struct aa_ns *sub; @@ -689,30 +765,31 @@ int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name) struct dentry *dent, *dir; int error; + AA_BUG(!ns); + AA_BUG(!parent); + AA_BUG(!mutex_is_locked(&ns->lock)); + if (!name) name = ns->base.name; + /* create ns dir if it doesn't already exist */ dent = securityfs_create_dir(name, parent); if (IS_ERR(dent)) goto fail; + ns_dir(ns) = dir = dent; + error = __aa_fs_ns_mkdir_entries(ns, dir); + if (error) + goto fail2; - dent = securityfs_create_dir("profiles", dir); - if (IS_ERR(dent)) - goto fail; - ns_subprofs_dir(ns) = dent; - - dent = securityfs_create_dir("namespaces", dir); - if (IS_ERR(dent)) - goto fail; - ns_subns_dir(ns) = dent; - + /* profiles */ list_for_each_entry(child, &ns->base.profiles, base.list) { error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns)); if (error) goto fail2; } + /* subnamespaces */ list_for_each_entry(sub, &ns->sub_ns, base.list) { mutex_lock(&sub->lock); error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL); @@ -1003,12 +1080,9 @@ static struct aa_fs_entry aa_fs_entry_features[] = { }; static struct aa_fs_entry aa_fs_entry_apparmor[] = { - AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load), - AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), - AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level), AA_FS_FILE_FOPS(".ns_name", 0640, &aa_fs_ns_name), - AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops), + AA_FS_FILE_FOPS("profiles", 0440, &aa_fs_profiles_fops), AA_FS_DIR("features", aa_fs_entry_features), { } }; @@ -1172,6 +1246,7 @@ out: */ static int __init aa_create_aafs(void) { + struct dentry *dent; int error; if (!apparmor_initialized) @@ -1187,7 +1262,34 @@ static int __init aa_create_aafs(void) if (error) goto error; + dent = securityfs_create_file(".load", 0666, aa_fs_entry.dentry, + NULL, &aa_fs_profile_load); + if (IS_ERR(dent)) { + error = PTR_ERR(dent); + goto error; + } + ns_subload(root_ns) = dent; + + dent = securityfs_create_file(".replace", 0666, aa_fs_entry.dentry, + NULL, &aa_fs_profile_replace); + if (IS_ERR(dent)) { + error = PTR_ERR(dent); + goto error; + } + ns_subreplace(root_ns) = dent; + + dent = securityfs_create_file(".remove", 0666, aa_fs_entry.dentry, + NULL, &aa_fs_profile_remove); + if (IS_ERR(dent)) { + error = PTR_ERR(dent); + goto error; + } + ns_subremove(root_ns) = dent; + + mutex_lock(&root_ns->lock); error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy"); + mutex_unlock(&root_ns->lock); + if (error) goto error; diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index a593e75b3b03..120a798b5bb0 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -71,6 +71,9 @@ enum aafs_ns_type { AAFS_NS_PROFS, AAFS_NS_NS, AAFS_NS_RAW_DATA, + AAFS_NS_LOAD, + AAFS_NS_REPLACE, + AAFS_NS_REMOVE, AAFS_NS_COUNT, AAFS_NS_MAX_COUNT, AAFS_NS_SIZE, @@ -96,6 +99,9 @@ enum aafs_prof_type { #define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS]) #define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS]) #define ns_subdata_dir(X) ((X)->dents[AAFS_NS_RAW_DATA]) +#define ns_subload(X) ((X)->dents[AAFS_NS_LOAD]) +#define ns_subreplace(X) ((X)->dents[AAFS_NS_REPLACE]) +#define ns_subremove(X) ((X)->dents[AAFS_NS_REMOVE]) #define prof_dir(X) ((X)->dents[AAFS_PROF_DIR]) #define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS]) From a20aa95fbe1abb4c6f333a1f55e9fd15b01c7f12 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:59 -0800 Subject: [PATCH 0418/1587] apparmor: fail task profile update if current_cred isn't real_cred Trying to update the task cred while the task current cred is not the real cred will result in an error at the cred layer. Avoid this by failing early and delaying the update. Signed-off-by: John Johansen --- security/apparmor/context.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 3c4f534ef88c..3f32f594c999 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -100,6 +100,9 @@ int aa_replace_current_profile(struct aa_profile *profile) if (cxt->profile == profile) return 0; + if (current_cred() != current_real_cred()) + return -EBUSY; + new = prepare_creds(); if (!new) return -ENOMEM; From 55a26ebf630b6bf1cb7ddf8882fdc81d58afeaa2 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:00 -0800 Subject: [PATCH 0419/1587] apparmor: rename context abreviation cxt to the more standard ctx Signed-off-by: John Johansen --- security/apparmor/context.c | 100 ++++++++++++++-------------- security/apparmor/domain.c | 42 ++++++------ security/apparmor/include/context.h | 78 +++++++++++----------- security/apparmor/lsm.c | 72 ++++++++++---------- security/apparmor/policy.c | 2 +- 5 files changed, 150 insertions(+), 144 deletions(-) diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 3f32f594c999..71e9910cca7b 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -13,11 +13,11 @@ * License. * * - * AppArmor sets confinement on every task, via the the aa_task_cxt and - * the aa_task_cxt.profile, both of which are required and are not allowed - * to be NULL. The aa_task_cxt is not reference counted and is unique + * AppArmor sets confinement on every task, via the the aa_task_ctx and + * the aa_task_ctx.profile, both of which are required and are not allowed + * to be NULL. The aa_task_ctx is not reference counted and is unique * to each cred (which is reference count). The profile pointed to by - * the task_cxt is reference counted. + * the task_ctx is reference counted. * * TODO * If a task uses change_hat it currently does not return to the old @@ -30,28 +30,28 @@ #include "include/policy.h" /** - * aa_alloc_task_context - allocate a new task_cxt + * aa_alloc_task_context - allocate a new task_ctx * @flags: gfp flags for allocation * * Returns: allocated buffer or NULL on failure */ -struct aa_task_cxt *aa_alloc_task_context(gfp_t flags) +struct aa_task_ctx *aa_alloc_task_context(gfp_t flags) { - return kzalloc(sizeof(struct aa_task_cxt), flags); + return kzalloc(sizeof(struct aa_task_ctx), flags); } /** - * aa_free_task_context - free a task_cxt - * @cxt: task_cxt to free (MAYBE NULL) + * aa_free_task_context - free a task_ctx + * @ctx: task_ctx to free (MAYBE NULL) */ -void aa_free_task_context(struct aa_task_cxt *cxt) +void aa_free_task_context(struct aa_task_ctx *ctx) { - if (cxt) { - aa_put_profile(cxt->profile); - aa_put_profile(cxt->previous); - aa_put_profile(cxt->onexec); + if (ctx) { + aa_put_profile(ctx->profile); + aa_put_profile(ctx->previous); + aa_put_profile(ctx->onexec); - kzfree(cxt); + kzfree(ctx); } } @@ -60,7 +60,7 @@ void aa_free_task_context(struct aa_task_cxt *cxt) * @new: a blank task context (NOT NULL) * @old: the task context to copy (NOT NULL) */ -void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old) +void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old) { *new = *old; aa_get_profile(new->profile); @@ -93,11 +93,11 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task) */ int aa_replace_current_profile(struct aa_profile *profile) { - struct aa_task_cxt *cxt = current_cxt(); + struct aa_task_ctx *ctx = current_ctx(); struct cred *new; BUG_ON(!profile); - if (cxt->profile == profile) + if (ctx->profile == profile) return 0; if (current_cred() != current_real_cred()) @@ -107,20 +107,22 @@ int aa_replace_current_profile(struct aa_profile *profile) if (!new) return -ENOMEM; - cxt = cred_cxt(new); - if (unconfined(profile) || (cxt->profile->ns != profile->ns)) + ctx = cred_ctx(new); + if (unconfined(profile) || (ctx->profile->ns != profile->ns)) /* if switching to unconfined or a different profile namespace * clear out context state */ - aa_clear_task_cxt_trans(cxt); + aa_clear_task_ctx_trans(ctx); - /* be careful switching cxt->profile, when racing replacement it - * is possible that cxt->profile->proxy->profile is the reference + /* + * be careful switching ctx->profile, when racing replacement it + * is possible that ctx->profile->proxy->profile is the reference * keeping @profile valid, so make sure to get its reference before - * dropping the reference on cxt->profile */ + * dropping the reference on ctx->profile + */ aa_get_profile(profile); - aa_put_profile(cxt->profile); - cxt->profile = profile; + aa_put_profile(ctx->profile); + ctx->profile = profile; commit_creds(new); return 0; @@ -134,15 +136,15 @@ int aa_replace_current_profile(struct aa_profile *profile) */ int aa_set_current_onexec(struct aa_profile *profile) { - struct aa_task_cxt *cxt; + struct aa_task_ctx *ctx; struct cred *new = prepare_creds(); if (!new) return -ENOMEM; - cxt = cred_cxt(new); + ctx = cred_ctx(new); aa_get_profile(profile); - aa_put_profile(cxt->onexec); - cxt->onexec = profile; + aa_put_profile(ctx->onexec); + ctx->onexec = profile; commit_creds(new); return 0; @@ -160,28 +162,28 @@ int aa_set_current_onexec(struct aa_profile *profile) */ int aa_set_current_hat(struct aa_profile *profile, u64 token) { - struct aa_task_cxt *cxt; + struct aa_task_ctx *ctx; struct cred *new = prepare_creds(); if (!new) return -ENOMEM; BUG_ON(!profile); - cxt = cred_cxt(new); - if (!cxt->previous) { + ctx = cred_ctx(new); + if (!ctx->previous) { /* transfer refcount */ - cxt->previous = cxt->profile; - cxt->token = token; - } else if (cxt->token == token) { - aa_put_profile(cxt->profile); + ctx->previous = ctx->profile; + ctx->token = token; + } else if (ctx->token == token) { + aa_put_profile(ctx->profile); } else { - /* previous_profile && cxt->token != token */ + /* previous_profile && ctx->token != token */ abort_creds(new); return -EACCES; } - cxt->profile = aa_get_newest_profile(profile); + ctx->profile = aa_get_newest_profile(profile); /* clear exec on switching context */ - aa_put_profile(cxt->onexec); - cxt->onexec = NULL; + aa_put_profile(ctx->onexec); + ctx->onexec = NULL; commit_creds(new); return 0; @@ -198,27 +200,27 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token) */ int aa_restore_previous_profile(u64 token) { - struct aa_task_cxt *cxt; + struct aa_task_ctx *ctx; struct cred *new = prepare_creds(); if (!new) return -ENOMEM; - cxt = cred_cxt(new); - if (cxt->token != token) { + ctx = cred_ctx(new); + if (ctx->token != token) { abort_creds(new); return -EACCES; } /* ignore restores when there is no saved profile */ - if (!cxt->previous) { + if (!ctx->previous) { abort_creds(new); return 0; } - aa_put_profile(cxt->profile); - cxt->profile = aa_get_newest_profile(cxt->previous); - BUG_ON(!cxt->profile); + aa_put_profile(ctx->profile); + ctx->profile = aa_get_newest_profile(ctx->previous); + AA_BUG(!ctx->profile); /* clear exec && prev information when restoring to previous context */ - aa_clear_task_cxt_trans(cxt); + aa_clear_task_ctx_trans(ctx); commit_creds(new); return 0; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 1a8ffc577009..84856b7bbee1 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -337,7 +337,7 @@ static struct aa_profile *x_to_profile(struct aa_profile *profile, */ int apparmor_bprm_set_creds(struct linux_binprm *bprm) { - struct aa_task_cxt *cxt; + struct aa_task_ctx *ctx; struct aa_profile *profile, *new_profile = NULL; struct aa_ns *ns; char *buffer = NULL; @@ -353,10 +353,10 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) if (bprm->cred_prepared) return 0; - cxt = cred_cxt(bprm->cred); - BUG_ON(!cxt); + ctx = cred_ctx(bprm->cred); + AA_BUG(!ctx); - profile = aa_get_newest_profile(cxt->profile); + profile = aa_get_newest_profile(ctx->profile); /* * get the namespace from the replacement profile as replacement * can change the namespace @@ -380,9 +380,9 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) */ if (unconfined(profile)) { /* unconfined task */ - if (cxt->onexec) + if (ctx->onexec) /* change_profile on exec already been granted */ - new_profile = aa_get_profile(cxt->onexec); + new_profile = aa_get_profile(ctx->onexec); else new_profile = find_attach(ns, &ns->base.profiles, name); if (!new_profile) @@ -397,10 +397,10 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) /* find exec permissions for name */ state = aa_str_perms(profile->file.dfa, state, name, &cond, &perms); - if (cxt->onexec) { + if (ctx->onexec) { struct file_perms cp; info = "change_profile onexec"; - new_profile = aa_get_newest_profile(cxt->onexec); + new_profile = aa_get_newest_profile(ctx->onexec); if (!(perms.allow & AA_MAY_ONEXEC)) goto audit; @@ -409,8 +409,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) * exec\0change_profile */ state = aa_dfa_null_transition(profile->file.dfa, state); - cp = change_profile_perms(profile, cxt->onexec->ns, - cxt->onexec->base.name, + cp = change_profile_perms(profile, ctx->onexec->ns, + ctx->onexec->base.name, AA_MAY_ONEXEC, state); if (!(cp.allow & AA_MAY_ONEXEC)) @@ -499,13 +499,13 @@ apply: bprm->per_clear |= PER_CLEAR_ON_SETID; x_clear: - aa_put_profile(cxt->profile); - /* transfer new profile reference will be released when cxt is freed */ - cxt->profile = new_profile; + aa_put_profile(ctx->profile); + /* transfer new profile reference will be released when ctx is freed */ + ctx->profile = new_profile; new_profile = NULL; /* clear out all temporary/transitional state from the context */ - aa_clear_task_cxt_trans(cxt); + aa_clear_task_ctx_trans(ctx); audit: error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC, @@ -545,17 +545,17 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm) void apparmor_bprm_committing_creds(struct linux_binprm *bprm) { struct aa_profile *profile = __aa_current_profile(); - struct aa_task_cxt *new_cxt = cred_cxt(bprm->cred); + struct aa_task_ctx *new_ctx = cred_ctx(bprm->cred); /* bail out if unconfined or not changing profile */ - if ((new_cxt->profile == profile) || - (unconfined(new_cxt->profile))) + if ((new_ctx->profile == profile) || + (unconfined(new_ctx->profile))) return; current->pdeath_signal = 0; /* reset soft limits and set hard limits for the new profile */ - __aa_transition_rlimits(profile, new_cxt->profile); + __aa_transition_rlimits(profile, new_ctx->profile); } /** @@ -604,7 +604,7 @@ static char *new_compound_name(const char *n1, const char *n2) int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) { const struct cred *cred; - struct aa_task_cxt *cxt; + struct aa_task_ctx *ctx; struct aa_profile *profile, *previous_profile, *hat = NULL; char *name = NULL; int i; @@ -622,9 +622,9 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) /* released below */ cred = get_current_cred(); - cxt = cred_cxt(cred); + ctx = cred_ctx(cred); profile = aa_get_newest_profile(aa_cred_profile(cred)); - previous_profile = aa_get_newest_profile(cxt->previous); + previous_profile = aa_get_newest_profile(ctx->previous); if (unconfined(profile)) { info = "unconfined"; diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index d378bff47ccd..5b18fedab4c8 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -22,43 +22,43 @@ #include "policy.h" #include "policy_ns.h" -#define cred_cxt(X) (X)->security -#define current_cxt() cred_cxt(current_cred()) +#define cred_ctx(X) ((X)->security) +#define current_ctx() cred_ctx(current_cred()) -/* struct aa_file_cxt - the AppArmor context the file was opened in +/* struct aa_file_ctx - the AppArmor context the file was opened in * @perms: the permission the file was opened with * - * The file_cxt could currently be directly stored in file->f_security + * The file_ctx could currently be directly stored in file->f_security * as the profile reference is now stored in the f_cred. However the - * cxt struct will expand in the future so we keep the struct. + * ctx struct will expand in the future so we keep the struct. */ -struct aa_file_cxt { +struct aa_file_ctx { u16 allow; }; /** - * aa_alloc_file_context - allocate file_cxt + * aa_alloc_file_context - allocate file_ctx * @gfp: gfp flags for allocation * - * Returns: file_cxt or NULL on failure + * Returns: file_ctx or NULL on failure */ -static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp) +static inline struct aa_file_ctx *aa_alloc_file_context(gfp_t gfp) { - return kzalloc(sizeof(struct aa_file_cxt), gfp); + return kzalloc(sizeof(struct aa_file_ctx), gfp); } /** - * aa_free_file_context - free a file_cxt - * @cxt: file_cxt to free (MAYBE_NULL) + * aa_free_file_context - free a file_ctx + * @ctx: file_ctx to free (MAYBE_NULL) */ -static inline void aa_free_file_context(struct aa_file_cxt *cxt) +static inline void aa_free_file_context(struct aa_file_ctx *ctx) { - if (cxt) - kzfree(cxt); + if (ctx) + kzfree(ctx); } /** - * struct aa_task_cxt - primary label for confined tasks + * struct aa_task_ctx - primary label for confined tasks * @profile: the current profile (NOT NULL) * @exec: profile to transition to on next exec (MAYBE NULL) * @previous: profile the task may return to (MAYBE NULL) @@ -69,17 +69,17 @@ static inline void aa_free_file_context(struct aa_file_cxt *cxt) * * TODO: make so a task can be confined by a stack of contexts */ -struct aa_task_cxt { +struct aa_task_ctx { struct aa_profile *profile; struct aa_profile *onexec; struct aa_profile *previous; u64 token; }; -struct aa_task_cxt *aa_alloc_task_context(gfp_t flags); -void aa_free_task_context(struct aa_task_cxt *cxt); -void aa_dup_task_context(struct aa_task_cxt *new, - const struct aa_task_cxt *old); +struct aa_task_ctx *aa_alloc_task_context(gfp_t flags); +void aa_free_task_context(struct aa_task_ctx *ctx); +void aa_dup_task_context(struct aa_task_ctx *new, + const struct aa_task_ctx *old); int aa_replace_current_profile(struct aa_profile *profile); int aa_set_current_onexec(struct aa_profile *profile); int aa_set_current_hat(struct aa_profile *profile, u64 token); @@ -97,9 +97,10 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task); */ static inline struct aa_profile *aa_cred_profile(const struct cred *cred) { - struct aa_task_cxt *cxt = cred_cxt(cred); - BUG_ON(!cxt || !cxt->profile); - return cxt->profile; + struct aa_task_ctx *ctx = cred_ctx(cred); + + AA_BUG(!ctx || !ctx->profile); + return ctx->profile; } /** @@ -149,18 +150,19 @@ static inline struct aa_profile *__aa_current_profile(void) */ static inline struct aa_profile *aa_current_profile(void) { - const struct aa_task_cxt *cxt = current_cxt(); + const struct aa_task_ctx *ctx = current_ctx(); struct aa_profile *profile; - BUG_ON(!cxt || !cxt->profile); - if (profile_is_stale(cxt->profile)) { - profile = aa_get_newest_profile(cxt->profile); + AA_BUG(!ctx || !ctx->profile); + + if (profile_is_stale(ctx->profile)) { + profile = aa_get_newest_profile(ctx->profile); aa_replace_current_profile(profile); aa_put_profile(profile); - cxt = current_cxt(); + ctx = current_ctx(); } - return cxt->profile; + return ctx->profile; } static inline struct aa_ns *aa_get_current_ns(void) @@ -169,16 +171,16 @@ static inline struct aa_ns *aa_get_current_ns(void) } /** - * aa_clear_task_cxt_trans - clear transition tracking info from the cxt - * @cxt: task context to clear (NOT NULL) + * aa_clear_task_ctx_trans - clear transition tracking info from the ctx + * @ctx: task context to clear (NOT NULL) */ -static inline void aa_clear_task_cxt_trans(struct aa_task_cxt *cxt) +static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) { - aa_put_profile(cxt->previous); - aa_put_profile(cxt->onexec); - cxt->previous = NULL; - cxt->onexec = NULL; - cxt->token = 0; + aa_put_profile(ctx->previous); + aa_put_profile(ctx->onexec); + ctx->previous = NULL; + ctx->onexec = NULL; + ctx->token = 0; } #endif /* __AA_CONTEXT_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 09f1c407c4d8..84666114e9f5 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -45,12 +45,12 @@ int apparmor_initialized __initdata; */ /* - * free the associated aa_task_cxt and put its profiles + * free the associated aa_task_ctx and put its profiles */ static void apparmor_cred_free(struct cred *cred) { - aa_free_task_context(cred_cxt(cred)); - cred_cxt(cred) = NULL; + aa_free_task_context(cred_ctx(cred)); + cred_ctx(cred) = NULL; } /* @@ -59,27 +59,29 @@ static void apparmor_cred_free(struct cred *cred) static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) { /* freed by apparmor_cred_free */ - struct aa_task_cxt *cxt = aa_alloc_task_context(gfp); - if (!cxt) + struct aa_task_ctx *ctx = aa_alloc_task_context(gfp); + + if (!ctx) return -ENOMEM; - cred_cxt(cred) = cxt; + cred_ctx(cred) = ctx; return 0; } /* - * prepare new aa_task_cxt for modification by prepare_cred block + * prepare new aa_task_ctx for modification by prepare_cred block */ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { /* freed by apparmor_cred_free */ - struct aa_task_cxt *cxt = aa_alloc_task_context(gfp); - if (!cxt) + struct aa_task_ctx *ctx = aa_alloc_task_context(gfp); + + if (!ctx) return -ENOMEM; - aa_dup_task_context(cxt, cred_cxt(old)); - cred_cxt(new) = cxt; + aa_dup_task_context(ctx, cred_ctx(old)); + cred_ctx(new) = ctx; return 0; } @@ -88,10 +90,10 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, */ static void apparmor_cred_transfer(struct cred *new, const struct cred *old) { - const struct aa_task_cxt *old_cxt = cred_cxt(old); - struct aa_task_cxt *new_cxt = cred_cxt(new); + const struct aa_task_ctx *old_ctx = cred_ctx(old); + struct aa_task_ctx *new_ctx = cred_ctx(new); - aa_dup_task_context(new_cxt, old_cxt); + aa_dup_task_context(new_ctx, old_ctx); } static int apparmor_ptrace_access_check(struct task_struct *child, @@ -345,7 +347,7 @@ static int apparmor_inode_getattr(const struct path *path) static int apparmor_file_open(struct file *file, const struct cred *cred) { - struct aa_file_cxt *fcxt = file->f_security; + struct aa_file_ctx *fctx = file->f_security; struct aa_profile *profile; int error = 0; @@ -358,7 +360,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) * actually execute the image. */ if (current->in_execve) { - fcxt->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP; + fctx->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP; return 0; } @@ -370,7 +372,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0, aa_map_file_to_perms(file), &cond); /* todo cache full allowed permissions set and state */ - fcxt->allow = aa_map_file_to_perms(file); + fctx->allow = aa_map_file_to_perms(file); } return error; @@ -388,14 +390,14 @@ static int apparmor_file_alloc_security(struct file *file) static void apparmor_file_free_security(struct file *file) { - struct aa_file_cxt *cxt = file->f_security; + struct aa_file_ctx *ctx = file->f_security; - aa_free_file_context(cxt); + aa_free_file_context(ctx); } static int common_file_perm(int op, struct file *file, u32 mask) { - struct aa_file_cxt *fcxt = file->f_security; + struct aa_file_ctx *fctx = file->f_security; struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred); int error = 0; @@ -415,7 +417,7 @@ static int common_file_perm(int op, struct file *file, u32 mask) * delegation from unconfined tasks */ if (!unconfined(profile) && !unconfined(fprofile) && - ((fprofile != profile) || (mask & ~fcxt->allow))) + ((fprofile != profile) || (mask & ~fctx->allow))) error = aa_file_perm(op, profile, file, mask); return error; @@ -477,15 +479,15 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, int error = -ENOENT; /* released below */ const struct cred *cred = get_task_cred(task); - struct aa_task_cxt *cxt = cred_cxt(cred); + struct aa_task_ctx *ctx = cred_ctx(cred); struct aa_profile *profile = NULL; if (strcmp(name, "current") == 0) - profile = aa_get_newest_profile(cxt->profile); - else if (strcmp(name, "prev") == 0 && cxt->previous) - profile = aa_get_newest_profile(cxt->previous); - else if (strcmp(name, "exec") == 0 && cxt->onexec) - profile = aa_get_newest_profile(cxt->onexec); + profile = aa_get_newest_profile(ctx->profile); + else if (strcmp(name, "prev") == 0 && ctx->previous) + profile = aa_get_newest_profile(ctx->previous); + else if (strcmp(name, "exec") == 0 && ctx->onexec) + profile = aa_get_newest_profile(ctx->onexec); else error = -EINVAL; @@ -849,21 +851,21 @@ static int param_set_mode(const char *val, struct kernel_param *kp) */ /** - * set_init_cxt - set a task context and profile on the first task. + * set_init_ctx - set a task context and profile on the first task. * * TODO: allow setting an alternate profile than unconfined */ -static int __init set_init_cxt(void) +static int __init set_init_ctx(void) { struct cred *cred = (struct cred *)current->real_cred; - struct aa_task_cxt *cxt; + struct aa_task_ctx *ctx; - cxt = aa_alloc_task_context(GFP_KERNEL); - if (!cxt) + ctx = aa_alloc_task_context(GFP_KERNEL); + if (!ctx) return -ENOMEM; - cxt->profile = aa_get_profile(root_ns->unconfined); - cred_cxt(cred) = cxt; + ctx->profile = aa_get_profile(root_ns->unconfined); + cred_ctx(cred) = ctx; return 0; } @@ -890,7 +892,7 @@ static int __init apparmor_init(void) goto alloc_out; } - error = set_init_cxt(); + error = set_init_ctx(); if (error) { AA_ERROR("Failed to set context on init task\n"); aa_free_root_ns(); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 912cdbed7977..4ec24474bd1a 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -808,7 +808,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, * @udata: serialized data stream (NOT NULL) * * unpack and replace a profile on the profile list and uses of that profile - * by any aa_task_cxt. If the profile does not exist on the profile list + * by any aa_task_ctx. If the profile does not exist on the profile list * it is added. * * Returns: size of data consumed else error code on failure. From 47f6e5cc7355e4ff2fd7ace919aa9e291077c26b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:01 -0800 Subject: [PATCH 0420/1587] apparmor: change op from int to const char * Having ops be an integer that is an index into an op name table is awkward and brittle. Every op change requires an edit for both the op constant and a string in the table. Instead switch to using const strings directly, eliminating the need for the table that needs to be kept in sync. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 4 +- security/apparmor/audit.c | 55 +----------------- security/apparmor/domain.c | 4 +- security/apparmor/file.c | 9 +-- security/apparmor/include/audit.h | 92 +++++++++++++++--------------- security/apparmor/include/file.h | 9 +-- security/apparmor/include/policy.h | 3 +- security/apparmor/lsm.c | 15 ++--- security/apparmor/policy.c | 7 ++- security/apparmor/procattr.c | 4 +- 10 files changed, 76 insertions(+), 126 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index af36af88c4ed..999a43e598f0 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -85,7 +85,7 @@ static int mangle_name(const char *name, char *target) * Returns: kernel buffer containing copy of user buffer data or an * ERR_PTR on failure. */ -static struct aa_loaddata *aa_simple_write_to_buffer(int op, +static struct aa_loaddata *aa_simple_write_to_buffer(const char *op, const char __user *userbuf, size_t alloc_size, size_t copy_size, @@ -122,7 +122,7 @@ static ssize_t policy_update(int binop, const char __user *buf, size_t size, ssize_t error; struct aa_loaddata *data; struct aa_profile *profile = aa_current_profile(); - int op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL; + const char *op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL; /* high level check about policy management - fine grained in * below after unpack */ diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 42101c42f446..bcd28d88df7b 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -20,59 +20,6 @@ #include "include/policy.h" #include "include/policy_ns.h" -const char *const op_table[] = { - "null", - - "sysctl", - "capable", - - "unlink", - "mkdir", - "rmdir", - "mknod", - "truncate", - "link", - "symlink", - "rename_src", - "rename_dest", - "chmod", - "chown", - "getattr", - "open", - - "file_perm", - "file_lock", - "file_mmap", - "file_mprotect", - - "create", - "post_create", - "bind", - "connect", - "listen", - "accept", - "sendmsg", - "recvmsg", - "getsockname", - "getpeername", - "getsockopt", - "setsockopt", - "socket_shutdown", - - "ptrace", - - "exec", - "change_hat", - "change_profile", - "change_onexec", - - "setprocattr", - "setrlimit", - - "profile_replace", - "profile_load", - "profile_remove" -}; const char *const audit_mode_names[] = { "normal", @@ -120,7 +67,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca) if (sa->aad->op) { audit_log_format(ab, " operation="); - audit_log_string(ab, op_table[sa->aad->op]); + audit_log_string(ab, sa->aad->op); } if (sa->aad->info) { diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 84856b7bbee1..c2f1d651db23 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -750,8 +750,8 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, struct aa_profile *profile, *target = NULL; struct aa_ns *ns = NULL; struct file_perms perms = {}; - const char *name = NULL, *info = NULL; - int op, error = 0; + const char *name = NULL, *info = NULL, *op; + int error = 0; u32 request; if (!hname && !ns_name) diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 608971ac6781..e04f044340ba 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -104,7 +104,7 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) * Returns: %0 or error on failure */ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, - gfp_t gfp, int op, u32 request, const char *name, + gfp_t gfp, const char *op, u32 request, const char *name, const char *target, kuid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; @@ -276,8 +276,9 @@ static inline bool is_deleted(struct dentry *dentry) * * Returns: %0 else error if access denied or other error */ -int aa_path_perm(int op, struct aa_profile *profile, const struct path *path, - int flags, u32 request, struct path_cond *cond) +int aa_path_perm(const char *op, struct aa_profile *profile, + const struct path *path, int flags, u32 request, + struct path_cond *cond) { char *buffer = NULL; struct file_perms perms = {}; @@ -446,7 +447,7 @@ audit: * * Returns: %0 if access allowed else error */ -int aa_file_perm(int op, struct aa_profile *profile, struct file *file, +int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file, u32 request) { struct path_cond cond = { diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index dbfb4a6d72b6..956c0b16a30f 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -46,65 +46,63 @@ enum audit_type { AUDIT_APPARMOR_AUTO }; -extern const char *const op_table[]; -enum aa_ops { - OP_NULL, +#define OP_NULL NULL - OP_SYSCTL, - OP_CAPABLE, +#define OP_SYSCTL "sysctl" +#define OP_CAPABLE "capable" - OP_UNLINK, - OP_MKDIR, - OP_RMDIR, - OP_MKNOD, - OP_TRUNC, - OP_LINK, - OP_SYMLINK, - OP_RENAME_SRC, - OP_RENAME_DEST, - OP_CHMOD, - OP_CHOWN, - OP_GETATTR, - OP_OPEN, +#define OP_UNLINK "unlink" +#define OP_MKDIR "mkdir" +#define OP_RMDIR "rmdir" +#define OP_MKNOD "mknod" +#define OP_TRUNC "truncate" +#define OP_LINK "link" +#define OP_SYMLINK "symlink" +#define OP_RENAME_SRC "rename_src" +#define OP_RENAME_DEST "rename_dest" +#define OP_CHMOD "chmod" +#define OP_CHOWN "chown" +#define OP_GETATTR "getattr" +#define OP_OPEN "open" - OP_FPERM, - OP_FLOCK, - OP_FMMAP, - OP_FMPROT, +#define OP_FPERM "file_perm" +#define OP_FLOCK "file_lock" +#define OP_FMMAP "file_mmap" +#define OP_FMPROT "file_mprotect" - OP_CREATE, - OP_POST_CREATE, - OP_BIND, - OP_CONNECT, - OP_LISTEN, - OP_ACCEPT, - OP_SENDMSG, - OP_RECVMSG, - OP_GETSOCKNAME, - OP_GETPEERNAME, - OP_GETSOCKOPT, - OP_SETSOCKOPT, - OP_SOCK_SHUTDOWN, +#define OP_CREATE "create" +#define OP_POST_CREATE "post_create" +#define OP_BIND "bind" +#define OP_CONNECT "connect" +#define OP_LISTEN "listen" +#define OP_ACCEPT "accept" +#define OP_SENDMSG "sendmsg" +#define OP_RECVMSG "recvmsg" +#define OP_GETSOCKNAME "getsockname" +#define OP_GETPEERNAME "getpeername" +#define OP_GETSOCKOPT "getsockopt" +#define OP_SETSOCKOPT "setsockopt" +#define OP_SHUTDOWN "socket_shutdown" - OP_PTRACE, +#define OP_PTRACE "ptrace" - OP_EXEC, - OP_CHANGE_HAT, - OP_CHANGE_PROFILE, - OP_CHANGE_ONEXEC, +#define OP_EXEC "exec" - OP_SETPROCATTR, - OP_SETRLIMIT, +#define OP_CHANGE_HAT "change_hat" +#define OP_CHANGE_PROFILE "change_profile" +#define OP_CHANGE_ONEXEC "change_onexec" - OP_PROF_REPL, - OP_PROF_LOAD, - OP_PROF_RM, -}; +#define OP_SETPROCATTR "setprocattr" +#define OP_SETRLIMIT "setrlimit" + +#define OP_PROF_REPL "profile_replace" +#define OP_PROF_LOAD "profile_load" +#define OP_PROF_RM "profile_remove" struct apparmor_audit_data { int error; - int op; + const char *op; int type; void *profile; const char *name; diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 4803c97d1992..0eb54363e033 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -145,7 +145,7 @@ static inline u16 dfa_map_xindex(u16 mask) dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff) int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, - gfp_t gfp, int op, u32 request, const char *name, + gfp_t gfp, const char *op, u32 request, const char *name, const char *target, kuid_t ouid, const char *info, int error); /** @@ -171,13 +171,14 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start, const char *name, struct path_cond *cond, struct file_perms *perms); -int aa_path_perm(int op, struct aa_profile *profile, const struct path *path, - int flags, u32 request, struct path_cond *cond); +int aa_path_perm(const char *op, struct aa_profile *profile, + const struct path *path, int flags, u32 request, + struct path_cond *cond); int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry); -int aa_file_perm(int op, struct aa_profile *profile, struct file *file, +int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file, u32 request); static inline void aa_free_file_rules(struct aa_file_rules *rules) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index b315ad5bdd85..a5a997896836 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -303,6 +303,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile) bool policy_view_capable(struct aa_ns *ns); bool policy_admin_capable(struct aa_ns *ns); -int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op); +int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, + const char *op); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 84666114e9f5..c751b033420c 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -152,7 +152,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, * * Returns: %0 else error code if error or permission denied */ -static int common_perm(int op, const struct path *path, u32 mask, +static int common_perm(const char *op, const struct path *path, u32 mask, struct path_cond *cond) { struct aa_profile *profile; @@ -175,7 +175,7 @@ static int common_perm(int op, const struct path *path, u32 mask, * * Returns: %0 else error code if error or permission denied */ -static int common_perm_dir_dentry(int op, const struct path *dir, +static int common_perm_dir_dentry(const char *op, const struct path *dir, struct dentry *dentry, u32 mask, struct path_cond *cond) { @@ -192,7 +192,8 @@ static int common_perm_dir_dentry(int op, const struct path *dir, * * Returns: %0 else error code if error or permission denied */ -static inline int common_perm_path(int op, const struct path *path, u32 mask) +static inline int common_perm_path(const char *op, const struct path *path, + u32 mask) { struct path_cond cond = { d_backing_inode(path->dentry)->i_uid, d_backing_inode(path->dentry)->i_mode @@ -212,7 +213,7 @@ static inline int common_perm_path(int op, const struct path *path, u32 mask) * * Returns: %0 else error code if error or permission denied */ -static int common_perm_rm(int op, const struct path *dir, +static int common_perm_rm(const char *op, const struct path *dir, struct dentry *dentry, u32 mask) { struct inode *inode = d_backing_inode(dentry); @@ -237,7 +238,7 @@ static int common_perm_rm(int op, const struct path *dir, * * Returns: %0 else error code if error or permission denied */ -static int common_perm_create(int op, const struct path *dir, +static int common_perm_create(const char *op, const struct path *dir, struct dentry *dentry, u32 mask, umode_t mode) { struct path_cond cond = { current_fsuid(), mode }; @@ -395,7 +396,7 @@ static void apparmor_file_free_security(struct file *file) aa_free_file_context(ctx); } -static int common_file_perm(int op, struct file *file, u32 mask) +static int common_file_perm(const char *op, struct file *file, u32 mask) { struct aa_file_ctx *fctx = file->f_security; struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred); @@ -438,7 +439,7 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd) return common_file_perm(OP_FLOCK, file, mask); } -static int common_mmap(int op, struct file *file, unsigned long prot, +static int common_mmap(const char *op, struct file *file, unsigned long prot, unsigned long flags) { int mask = 0; diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4ec24474bd1a..17754ee58ff1 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -606,7 +606,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: the error to be returned after audit is done */ -static int audit_policy(struct aa_profile *profile, int op, gfp_t gfp, +static int audit_policy(struct aa_profile *profile, const char *op, gfp_t gfp, const char *nsname, const char *name, const char *info, int error) { @@ -670,7 +670,8 @@ bool policy_admin_capable(struct aa_ns *ns) * * Returns: 0 if the task is allowed to manipulate policy else error */ -int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op) +int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, + const char *op) { /* check if loading policy is locked out */ if (aa_g_lock_policy) @@ -819,7 +820,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; struct aa_load_ent *ent, *tmp; - int op = OP_PROF_REPL; + const char *op = OP_PROF_REPL; ssize_t count, error; LIST_HEAD(lh); diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index 1babd3655520..4cb5f3dc906d 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -88,13 +88,13 @@ int aa_getprocattr(struct aa_profile *profile, char **string) * * Returns: start position of name after token else NULL on failure */ -static char *split_token_from_name(int op, char *args, u64 * token) +static char *split_token_from_name(const char *op, char *args, u64 *token) { char *name; *token = simple_strtoull(args, &name, 16); if ((name == args) || *name != '^') { - AA_ERROR("%s: Invalid input '%s'", op_table[op], args); + AA_ERROR("%s: Invalid input '%s'", op, args); return ERR_PTR(-EINVAL); } From ef88a7ac55fdd3bf6ac3942b83aa29311b45339b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:02 -0800 Subject: [PATCH 0421/1587] apparmor: change aad apparmor_audit_data macro to a fn macro The aad macro can replace aad strings when it is not intended to. Switch to a fn macro so it is only applied when intended. Also at the same time cleanup audit_data initialization by putting common boiler plate behind a macro, and dropping the gfp_t parameter which will become useless. Signed-off-by: John Johansen --- security/apparmor/audit.c | 42 +++++++++---------- security/apparmor/capability.c | 10 ++--- security/apparmor/domain.c | 13 +++--- security/apparmor/file.c | 69 +++++++++++++++---------------- security/apparmor/include/audit.h | 43 +++++++++++++------ security/apparmor/include/file.h | 2 +- security/apparmor/ipc.c | 18 ++++---- security/apparmor/lib.c | 8 ++-- security/apparmor/lsm.c | 12 ++---- security/apparmor/policy.c | 40 ++++++++---------- security/apparmor/policy_unpack.c | 38 +++++++++-------- security/apparmor/resource.c | 17 +++----- 12 files changed, 153 insertions(+), 159 deletions(-) diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index bcd28d88df7b..0c81ff64993b 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -62,23 +62,23 @@ static void audit_pre(struct audit_buffer *ab, void *ca) if (aa_g_audit_header) { audit_log_format(ab, "apparmor="); - audit_log_string(ab, aa_audit_type[sa->aad->type]); + audit_log_string(ab, aa_audit_type[aad(sa)->type]); } - if (sa->aad->op) { + if (aad(sa)->op) { audit_log_format(ab, " operation="); - audit_log_string(ab, sa->aad->op); + audit_log_string(ab, aad(sa)->op); } - if (sa->aad->info) { + if (aad(sa)->info) { audit_log_format(ab, " info="); - audit_log_string(ab, sa->aad->info); - if (sa->aad->error) - audit_log_format(ab, " error=%d", sa->aad->error); + audit_log_string(ab, aad(sa)->info); + if (aad(sa)->error) + audit_log_format(ab, " error=%d", aad(sa)->error); } - if (sa->aad->profile) { - struct aa_profile *profile = sa->aad->profile; + if (aad(sa)->profile) { + struct aa_profile *profile = aad(sa)->profile; if (profile->ns != root_ns) { audit_log_format(ab, " namespace="); audit_log_untrustedstring(ab, profile->ns->base.hname); @@ -87,9 +87,9 @@ static void audit_pre(struct audit_buffer *ab, void *ca) audit_log_untrustedstring(ab, profile->base.hname); } - if (sa->aad->name) { + if (aad(sa)->name) { audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, sa->aad->name); + audit_log_untrustedstring(ab, aad(sa)->name); } } @@ -101,7 +101,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca) void aa_audit_msg(int type, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)) { - sa->aad->type = type; + aad(sa)->type = type; common_lsm_audit(sa, audit_pre, cb); } @@ -109,7 +109,6 @@ void aa_audit_msg(int type, struct common_audit_data *sa, * aa_audit - Log a profile based audit event to the audit subsystem * @type: audit type for the message * @profile: profile to check against (NOT NULL) - * @gfp: allocation flags to use * @sa: audit event (NOT NULL) * @cb: optional callback fn for type specific fields (MAYBE NULL) * @@ -117,14 +116,13 @@ void aa_audit_msg(int type, struct common_audit_data *sa, * * Returns: error on failure */ -int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, - struct common_audit_data *sa, +int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)) { BUG_ON(!profile); if (type == AUDIT_APPARMOR_AUTO) { - if (likely(!sa->aad->error)) { + if (likely(!aad(sa)->error)) { if (AUDIT_MODE(profile) != AUDIT_ALL) return 0; type = AUDIT_APPARMOR_AUDIT; @@ -136,23 +134,23 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, if (AUDIT_MODE(profile) == AUDIT_QUIET || (type == AUDIT_APPARMOR_DENIED && AUDIT_MODE(profile) == AUDIT_QUIET)) - return sa->aad->error; + return aad(sa)->error; if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) type = AUDIT_APPARMOR_KILL; if (!unconfined(profile)) - sa->aad->profile = profile; + aad(sa)->profile = profile; aa_audit_msg(type, sa, cb); - if (sa->aad->type == AUDIT_APPARMOR_KILL) + if (aad(sa)->type == AUDIT_APPARMOR_KILL) (void)send_sig_info(SIGKILL, NULL, sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ? sa->u.tsk : current); - if (sa->aad->type == AUDIT_APPARMOR_ALLOWED) - return complain_error(sa->aad->error); + if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED) + return complain_error(aad(sa)->error); - return sa->aad->error; + return aad(sa)->error; } diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 1101c6f64bb7..1d2e2de5515f 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c @@ -66,13 +66,9 @@ static int audit_caps(struct aa_profile *profile, int cap, int error) { struct audit_cache *ent; int type = AUDIT_APPARMOR_AUTO; - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_CAP; - sa.aad = &aad; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); sa.u.cap = cap; - sa.aad->op = OP_CAPABLE; - sa.aad->error = error; + aad(&sa)->error = error; if (likely(!error)) { /* test if auditing is being forced */ @@ -104,7 +100,7 @@ static int audit_caps(struct aa_profile *profile, int cap, int error) } put_cpu_var(audit_cache); - return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb); + return aa_audit(type, profile, &sa, audit_cb); } /** diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index c2f1d651db23..d18b3f0e5534 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -508,8 +508,7 @@ x_clear: aa_clear_task_ctx_trans(ctx); audit: - error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC, - name, + error = aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, new_profile ? new_profile->base.hname : NULL, cond.uid, info, error); @@ -714,9 +713,9 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) audit: if (!permtest) - error = aa_audit_file(profile, &perms, GFP_KERNEL, - OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL, - target, GLOBAL_ROOT_UID, info, error); + error = aa_audit_file(profile, &perms, OP_CHANGE_HAT, + AA_MAY_CHANGEHAT, NULL, target, + GLOBAL_ROOT_UID, info, error); out: aa_put_profile(hat); @@ -842,8 +841,8 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, audit: if (!permtest) - error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, - name, hname, GLOBAL_ROOT_UID, info, error); + error = aa_audit_file(profile, &perms, op, request, name, + hname, GLOBAL_ROOT_UID, info, error); aa_put_ns(ns); aa_put_profile(target); diff --git a/security/apparmor/file.c b/security/apparmor/file.c index e04f044340ba..750564c3ab71 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -67,24 +67,24 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) struct common_audit_data *sa = va; kuid_t fsuid = current_fsuid(); - if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) { + if (aad(sa)->fs.request & AA_AUDIT_FILE_MASK) { audit_log_format(ab, " requested_mask="); - audit_file_mask(ab, sa->aad->fs.request); + audit_file_mask(ab, aad(sa)->fs.request); } - if (sa->aad->fs.denied & AA_AUDIT_FILE_MASK) { + if (aad(sa)->fs.denied & AA_AUDIT_FILE_MASK) { audit_log_format(ab, " denied_mask="); - audit_file_mask(ab, sa->aad->fs.denied); + audit_file_mask(ab, aad(sa)->fs.denied); } - if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) { + if (aad(sa)->fs.request & AA_AUDIT_FILE_MASK) { audit_log_format(ab, " fsuid=%d", from_kuid(&init_user_ns, fsuid)); audit_log_format(ab, " ouid=%d", - from_kuid(&init_user_ns, sa->aad->fs.ouid)); + from_kuid(&init_user_ns, aad(sa)->fs.ouid)); } - if (sa->aad->fs.target) { + if (aad(sa)->fs.target) { audit_log_format(ab, " target="); - audit_log_untrustedstring(ab, sa->aad->fs.target); + audit_log_untrustedstring(ab, aad(sa)->fs.target); } } @@ -104,54 +104,53 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) * Returns: %0 or error on failure */ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, - gfp_t gfp, const char *op, u32 request, const char *name, + const char *op, u32 request, const char *name, const char *target, kuid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_TASK; - sa.u.tsk = NULL; - sa.aad = &aad; - aad.op = op, - aad.fs.request = request; - aad.name = name; - aad.fs.target = target; - aad.fs.ouid = ouid; - aad.info = info; - aad.error = error; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, op); - if (likely(!sa.aad->error)) { + sa.u.tsk = NULL; + aad(&sa)->fs.request = request; + aad(&sa)->name = name; + aad(&sa)->fs.target = target; + aad(&sa)->fs.ouid = ouid; + aad(&sa)->info = info; + aad(&sa)->error = error; + sa.u.tsk = NULL; + + if (likely(!aad(&sa)->error)) { u32 mask = perms->audit; if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) mask = 0xffff; /* mask off perms that are not being force audited */ - sa.aad->fs.request &= mask; + aad(&sa)->fs.request &= mask; - if (likely(!sa.aad->fs.request)) + if (likely(!aad(&sa)->fs.request)) return 0; type = AUDIT_APPARMOR_AUDIT; } else { /* only report permissions that were denied */ - sa.aad->fs.request = sa.aad->fs.request & ~perms->allow; + aad(&sa)->fs.request = aad(&sa)->fs.request & ~perms->allow; + AA_BUG(!aad(&sa)->fs.request); - if (sa.aad->fs.request & perms->kill) + if (aad(&sa)->fs.request & perms->kill) type = AUDIT_APPARMOR_KILL; /* quiet known rejects, assumes quiet and kill do not overlap */ - if ((sa.aad->fs.request & perms->quiet) && + if ((aad(&sa)->fs.request & perms->quiet) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) - sa.aad->fs.request &= ~perms->quiet; + aad(&sa)->fs.request &= ~perms->quiet; - if (!sa.aad->fs.request) - return COMPLAIN_MODE(profile) ? 0 : sa.aad->error; + if (!aad(&sa)->fs.request) + return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error; } - sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow; - return aa_audit(type, profile, gfp, &sa, file_audit_cb); + aad(&sa)->fs.denied = aad(&sa)->fs.request & ~perms->allow; + return aa_audit(type, profile, &sa, file_audit_cb); } /** @@ -302,8 +301,8 @@ int aa_path_perm(const char *op, struct aa_profile *profile, if (request & ~perms.allow) error = -EACCES; } - error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name, - NULL, cond->uid, info, error); + error = aa_audit_file(profile, &perms, op, request, name, NULL, + cond->uid, info, error); kfree(buffer); return error; @@ -430,7 +429,7 @@ done_tests: error = 0; audit: - error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request, + error = aa_audit_file(profile, &lperms, OP_LINK, request, lname, tname, cond.uid, info, error); kfree(buffer); kfree(buffer2); diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 956c0b16a30f..fdc4774318ba 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -108,34 +108,53 @@ struct apparmor_audit_data { const char *name; const char *info; union { - void *target; + /* these entries require a custom callback fn */ struct { + struct aa_profile *peer; + struct { + const char *target; + u32 request; + u32 denied; + kuid_t ouid; + } fs; + }; + struct { + const char *name; long pos; const char *ns; - void *target; } iface; struct { int rlim; unsigned long max; } rlim; - struct { - const char *target; - u32 request; - u32 denied; - kuid_t ouid; - } fs; }; }; -/* define a short hand for apparmor_audit_data structure */ -#define aad apparmor_audit_data +/* macros for dealing with apparmor_audit_data structure */ +#define aad(SA) ((SA)->apparmor_audit_data) +#define DEFINE_AUDIT_DATA(NAME, T, X) \ + /* TODO: cleanup audit init so we don't need _aad = {0,} */ \ + struct apparmor_audit_data NAME ## _aad = { .op = (X), }; \ + struct common_audit_data NAME = \ + { \ + .type = (T), \ + .u.tsk = NULL, \ + }; \ + NAME.apparmor_audit_data = &(NAME ## _aad) void aa_audit_msg(int type, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)); -int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, - struct common_audit_data *sa, +int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)); +#define aa_audit_error(ERROR, SA, CB) \ +({ \ + aad((SA))->error = (ERROR); \ + aa_audit_msg(AUDIT_APPARMOR_ERROR, (SA), (CB)); \ + aad((SA))->error; \ +}) + + static inline int complain_error(int error) { if (error == -EPERM || error == -EACCES) diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 0eb54363e033..38f821bf49b6 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -145,7 +145,7 @@ static inline u16 dfa_map_xindex(u16 mask) dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff) int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, - gfp_t gfp, const char *op, u32 request, const char *name, + const char *op, u32 request, const char *name, const char *target, kuid_t ouid, const char *info, int error); /** diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index 777ac1c47253..edac790923c3 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -25,8 +25,8 @@ static void audit_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; - audit_log_format(ab, " target="); - audit_log_untrustedstring(ab, sa->aad->target); + audit_log_format(ab, " peer="); + audit_log_untrustedstring(ab, aad(sa)->peer->base.hname); } /** @@ -40,16 +40,12 @@ static void audit_cb(struct audit_buffer *ab, void *va) static int aa_audit_ptrace(struct aa_profile *profile, struct aa_profile *target, int error) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = OP_PTRACE; - aad.target = target; - aad.error = error; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); - return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa, - audit_cb); + aad(&sa)->peer = target; + aad(&sa)->error = error; + + return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb); } /** diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 5d8ef31a60f1..66475bda6f72 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -120,11 +120,9 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, void aa_info_message(const char *str) { if (audit_enabled) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.info = str; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); + + aad(&sa)->info = str; aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); } printk(KERN_INFO "AppArmor: %s\n", str); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index c751b033420c..c4bae8ae538f 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -504,11 +504,10 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, static int apparmor_setprocattr(struct task_struct *task, char *name, void *value, size_t size) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; char *command, *largs = NULL, *args = value; size_t arg_size; int error; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETPROCATTR); if (size == 0) return -EINVAL; @@ -568,12 +567,9 @@ out: return error; fail: - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.profile = aa_current_profile(); - aad.op = OP_SETPROCATTR; - aad.info = name; - aad.error = error = -EINVAL; + aad(&sa)->profile = aa_current_profile(); + aad(&sa)->info = name; + aad(&sa)->error = error = -EINVAL; aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL); goto out; } diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 17754ee58ff1..bc63cf7b606a 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -588,9 +588,9 @@ static void audit_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; - if (sa->aad->iface.ns) { + if (aad(sa)->iface.ns) { audit_log_format(ab, " ns="); - audit_log_untrustedstring(ab, sa->aad->iface.ns); + audit_log_untrustedstring(ab, aad(sa)->iface.ns); } } @@ -606,22 +606,18 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: the error to be returned after audit is done */ -static int audit_policy(struct aa_profile *profile, const char *op, gfp_t gfp, +static int audit_policy(struct aa_profile *profile, const char *op, const char *nsname, const char *name, const char *info, int error) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = op; - aad.iface.ns = nsname; - aad.name = name; - aad.info = info; - aad.error = error; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op); - return aa_audit(AUDIT_APPARMOR_STATUS, profile, gfp, - &sa, audit_cb); + aad(&sa)->iface.ns = nsname; + aad(&sa)->name = name; + aad(&sa)->info = info; + aad(&sa)->error = error; + + return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb); } /** @@ -675,11 +671,11 @@ int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, { /* check if loading policy is locked out */ if (aa_g_lock_policy) - return audit_policy(profile, op, GFP_KERNEL, NULL, NULL, + return audit_policy(profile, op, NULL, NULL, "policy_locked", -EACCES); if (!policy_admin_capable(ns)) - return audit_policy(profile, op, GFP_KERNEL, NULL, NULL, + return audit_policy(profile, op, NULL, NULL, "not policy admin", -EACCES); /* TODO: add fine grained mediation of policy loads */ @@ -937,8 +933,8 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, list_del_init(&ent->list); op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(profile, op, GFP_ATOMIC, NULL, - ent->new->base.hname, NULL, error); + audit_policy(profile, op, NULL, ent->new->base.hname, + NULL, error); if (ent->old) { __replace_profile(ent->old, ent->new, 1); @@ -993,7 +989,7 @@ fail_lock: /* audit cause of failure */ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; fail: - audit_policy(profile, op, GFP_KERNEL, ns_name, ent->new->base.hname, + audit_policy(profile, op, ns_name, ent->new->base.hname, info, error); /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; @@ -1004,7 +1000,7 @@ fail: continue; } op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(profile, op, GFP_KERNEL, ns_name, + audit_policy(profile, op, ns_name, tmp->new->base.hname, info, error); } list_for_each_entry_safe(ent, tmp, &lh, list) { @@ -1079,7 +1075,7 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj, } /* don't fail removal if audit fails */ - (void) audit_policy(subj, OP_PROF_RM, GFP_KERNEL, ns_name, name, info, + (void) audit_policy(subj, OP_PROF_RM, ns_name, name, info, error); aa_put_ns(ns); aa_put_profile(profile); @@ -1090,7 +1086,7 @@ fail_ns_lock: aa_put_ns(ns); fail: - (void) audit_policy(subj, OP_PROF_RM, GFP_KERNEL, ns_name, name, info, + (void) audit_policy(subj, OP_PROF_RM, ns_name, name, info, error); return error; } diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 38c148f33fa4..441efc965f2b 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -79,13 +79,17 @@ struct aa_ext { static void audit_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; - if (sa->aad->iface.target) { - struct aa_profile *name = sa->aad->iface.target; - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, name->base.hname); + + if (aad(sa)->iface.ns) { + audit_log_format(ab, " ns="); + audit_log_untrustedstring(ab, aad(sa)->iface.ns); } - if (sa->aad->iface.pos) - audit_log_format(ab, " offset=%ld", sa->aad->iface.pos); + if (aad(sa)->iface.name) { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, aad(sa)->iface.name); + } + if (aad(sa)->iface.pos) + audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos); } /** @@ -104,20 +108,18 @@ static int audit_iface(struct aa_profile *new, const char *ns_name, int error) { struct aa_profile *profile = __aa_current_profile(); - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.iface.ns = ns_name; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); if (e) - aad.iface.pos = e->pos - e->start; - aad.iface.target = new; - aad.name = name; - aad.info = info; - aad.error = error; + aad(&sa)->iface.pos = e->pos - e->start; + aad(&sa)->iface.ns = ns_name; + if (new) + aad(&sa)->iface.name = new->base.hname; + else + aad(&sa)->iface.name = name; + aad(&sa)->info = info; + aad(&sa)->error = error; - return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa, - audit_cb); + return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb); } void aa_loaddata_kref(struct kref *kref) diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index 67a6072ead4b..86a941afd956 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -35,7 +35,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) struct common_audit_data *sa = va; audit_log_format(ab, " rlimit=%s value=%lu", - rlim_names[sa->aad->rlim.rlim], sa->aad->rlim.max); + rlim_names[aad(sa)->rlim.rlim], aad(sa)->rlim.max); } /** @@ -50,17 +50,12 @@ static void audit_cb(struct audit_buffer *ab, void *va) static int audit_resource(struct aa_profile *profile, unsigned int resource, unsigned long value, int error) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETRLIMIT); - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = OP_SETRLIMIT, - aad.rlim.rlim = resource; - aad.rlim.max = value; - aad.error = error; - return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa, - audit_cb); + aad(&sa)->rlim.rlim = resource; + aad(&sa)->rlim.max = value; + aad(&sa)->error = error; + return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb); } /** From 5ef50d014c59240c2cac38594377583c4e9ea4fa Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:03 -0800 Subject: [PATCH 0422/1587] apparmor: remove unused op parameter from simple_write_to_buffer() Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 999a43e598f0..fd0d9e38b6c6 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -76,7 +76,6 @@ static int mangle_name(const char *name, char *target) /** * aa_simple_write_to_buffer - common routine for getting policy from user - * @op: operation doing the user buffer copy * @userbuf: user buffer to copy data from (NOT NULL) * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size) * @copy_size: size of data to copy from user buffer @@ -85,8 +84,7 @@ static int mangle_name(const char *name, char *target) * Returns: kernel buffer containing copy of user buffer data or an * ERR_PTR on failure. */ -static struct aa_loaddata *aa_simple_write_to_buffer(const char *op, - const char __user *userbuf, +static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, size_t alloc_size, size_t copy_size, loff_t *pos) @@ -130,7 +128,7 @@ static ssize_t policy_update(int binop, const char __user *buf, size_t size, if (error) return error; - data = aa_simple_write_to_buffer(op, buf, size, size, pos); + data = aa_simple_write_to_buffer(buf, size, size, pos); error = PTR_ERR(data); if (!IS_ERR(data)) { error = aa_replace_profiles(ns ? ns : profile->ns, profile, @@ -196,8 +194,7 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, * aa_remove_profile needs a null terminated string so 1 extra * byte is allocated and the copied data is null terminated. */ - data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, - pos); + data = aa_simple_write_to_buffer(buf, size + 1, size, pos); error = PTR_ERR(data); if (!IS_ERR(data)) { From c3e1e584ad3853b3f13ea4bd0aabd43e6c9b9fda Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:05 -0800 Subject: [PATCH 0423/1587] apparmor: fix change_hat debug output Signed-off-by: John Johansen --- security/apparmor/procattr.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index 4cb5f3dc906d..a9a9ee6659ae 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -139,12 +139,13 @@ int aa_setprocattr_changehat(char *args, size_t size, int test) for (count = 0; (hat < end) && count < 16; ++count) { char *next = hat + strlen(hat) + 1; hats[count] = hat; + AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n" + , __func__, current->pid, token, count, hat); hat = next; } - } - - AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n", - __func__, token, hat ? hat : NULL); + } else + AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n", + __func__, current->pid, token, count, ""); return aa_change_hat(hats, count, token, test); } From aa9a39ad8f60cc73e1bd2f18f0693bba6be8b067 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:06 -0800 Subject: [PATCH 0424/1587] apparmor: convert change_profile to use fqname later to give better control Moving the use of fqname to later allows learning profiles to be based on the fqname request instead of just the hname. It also allows cleaning up some of the name parsing and lookup by allowing the use of the fqlookupn_profile() lib fn. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 1 + security/apparmor/domain.c | 61 ++++++++++-------------------- security/apparmor/include/domain.h | 4 +- security/apparmor/lsm.c | 12 +++--- security/apparmor/procattr.c | 16 -------- 5 files changed, 28 insertions(+), 66 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index fd0d9e38b6c6..7613a28f157e 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1052,6 +1052,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = { AA_FS_FILE_BOOLEAN("change_onexec", 1), AA_FS_FILE_BOOLEAN("change_profile", 1), AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1), + AA_FS_FILE_STRING("version", "1.2"), { } }; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index d18b3f0e5534..ef4beef06e9d 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -729,8 +729,7 @@ out: /** * aa_change_profile - perform a one-way profile transition - * @ns_name: name of the profile namespace to change to (MAYBE NULL) - * @hname: name of profile to change to (MAYBE NULL) + * @fqname: name of profile may include namespace (NOT NULL) * @onexec: whether this transition is to take place immediately or at exec * @permtest: true if this is just a permission test * @@ -742,19 +741,20 @@ out: * * Returns %0 on success, error otherwise. */ -int aa_change_profile(const char *ns_name, const char *hname, bool onexec, - bool permtest) +int aa_change_profile(const char *fqname, bool onexec, + bool permtest, bool stack) { const struct cred *cred; struct aa_profile *profile, *target = NULL; - struct aa_ns *ns = NULL; struct file_perms perms = {}; - const char *name = NULL, *info = NULL, *op; + const char *info = NULL, *op; int error = 0; u32 request; - if (!hname && !ns_name) + if (!fqname || !*fqname) { + AA_DEBUG("no profile name"); return -EINVAL; + } if (onexec) { request = AA_MAY_ONEXEC; @@ -779,44 +779,15 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, return -EPERM; } - if (ns_name) { - /* released below */ - ns = aa_find_ns(profile->ns, ns_name); - if (!ns) { - /* we don't create new namespace in complain mode */ - name = ns_name; - info = "namespace not found"; - error = -ENOENT; - goto audit; - } - } else - /* released below */ - ns = aa_get_ns(profile->ns); - - /* if the name was not specified, use the name of the current profile */ - if (!hname) { - if (unconfined(profile)) - hname = ns->unconfined->base.hname; - else - hname = profile->base.hname; - } - - perms = change_profile_perms(profile, ns, hname, request, - profile->file.start); - if (!(perms.allow & request)) { - error = -EACCES; - goto audit; - } - - /* released below */ - target = aa_lookup_profile(ns, hname); + target = aa_fqlookupn_profile(profile, fqname, strlen(fqname)); if (!target) { info = "profile not found"; error = -ENOENT; if (permtest || !COMPLAIN_MODE(profile)) goto audit; /* released below */ - target = aa_new_null_profile(profile, false, hname, GFP_KERNEL); + target = aa_new_null_profile(profile, false, fqname, + GFP_KERNEL); if (!target) { info = "failed null profile create"; error = -ENOMEM; @@ -824,6 +795,13 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, } } + perms = change_profile_perms(profile, target->ns, target->base.hname, + request, profile->file.start); + if (!(perms.allow & request)) { + error = -EACCES; + goto audit; + } + /* check if tracing task is allowed to trace target domain */ error = may_change_ptraced_domain(target); if (error) { @@ -841,10 +819,9 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, audit: if (!permtest) - error = aa_audit_file(profile, &perms, op, request, name, - hname, GLOBAL_ROOT_UID, info, error); + error = aa_audit_file(profile, &perms, op, request, NULL, + fqname, GLOBAL_ROOT_UID, info, error); - aa_put_ns(ns); aa_put_profile(target); put_cred(cred); diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h index de04464f0a3f..30544729878a 100644 --- a/security/apparmor/include/domain.h +++ b/security/apparmor/include/domain.h @@ -30,7 +30,7 @@ void apparmor_bprm_committed_creds(struct linux_binprm *bprm); void aa_free_domain_entries(struct aa_domain *domain); int aa_change_hat(const char *hats[], int count, u64 token, bool permtest); -int aa_change_profile(const char *ns_name, const char *name, bool onexec, - bool permtest); +int aa_change_profile(const char *fqname, bool onexec, bool permtest, + bool stack); #endif /* __AA_DOMAIN_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index c4bae8ae538f..264aa192032e 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -543,17 +543,17 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, error = aa_setprocattr_changehat(args, arg_size, AA_DO_TEST); } else if (strcmp(command, "changeprofile") == 0) { - error = aa_setprocattr_changeprofile(args, !AA_ONEXEC, - !AA_DO_TEST); + error = aa_change_profile(args, !AA_ONEXEC, + !AA_DO_TEST, false); } else if (strcmp(command, "permprofile") == 0) { - error = aa_setprocattr_changeprofile(args, !AA_ONEXEC, - AA_DO_TEST); + error = aa_change_profile(args, !AA_ONEXEC, AA_DO_TEST, + false); } else goto fail; } else if (strcmp(name, "exec") == 0) { if (strcmp(command, "exec") == 0) - error = aa_setprocattr_changeprofile(args, AA_ONEXEC, - !AA_DO_TEST); + error = aa_change_profile(args, AA_ONEXEC, !AA_DO_TEST, + false); else goto fail; } else diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index a9a9ee6659ae..3466a27bca09 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -149,19 +149,3 @@ int aa_setprocattr_changehat(char *args, size_t size, int test) return aa_change_hat(hats, count, token, test); } - -/** - * aa_setprocattr_changeprofile - handle procattr interface to changeprofile - * @fqname: args received from writting to /proc//attr/current (NOT NULL) - * @onexec: true if change_profile should be delayed until exec - * @test: true if this is a test of change_profile permissions - * - * Returns: %0 or error code if change_profile fails - */ -int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test) -{ - char *name, *ns_name; - - name = aa_split_fqname(fqname, &ns_name); - return aa_change_profile(ns_name, name, onexec, test); -} From 31f75bfecd9cef7d485b1cda3c6c38cc0b4a5c6c Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:07 -0800 Subject: [PATCH 0425/1587] apparmor: make computing policy hashes conditional on kernel parameter Allow turning off the computation of the policy hashes via the apparmor.hash_policy kernel parameter. Signed-off-by: John Johansen --- security/apparmor/lsm.c | 48 +++++++++++++++---------------- security/apparmor/policy_unpack.c | 15 ++++++---- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 264aa192032e..6a5cf54cfa72 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -165,6 +165,26 @@ static int common_perm(const char *op, const struct path *path, u32 mask, return error; } +/** + * common_perm_cond - common permission wrapper around inode cond + * @op: operation being checked + * @path: location to check (NOT NULL) + * @mask: requested permissions mask + * + * Returns: %0 else error code if error or permission denied + */ +static int common_perm_cond(const char *op, const struct path *path, u32 mask) +{ + struct path_cond cond = { d_backing_inode(path->dentry)->i_uid, + d_backing_inode(path->dentry)->i_mode + }; + + if (!path_mediated_fs(path->dentry)) + return 0; + + return common_perm(op, path, mask, &cond); +} + /** * common_perm_dir_dentry - common permission wrapper when path is dir, dentry * @op: operation being checked @@ -184,26 +204,6 @@ static int common_perm_dir_dentry(const char *op, const struct path *dir, return common_perm(op, &path, mask, cond); } -/** - * common_perm_path - common permission wrapper when mnt, dentry - * @op: operation being checked - * @path: location to check (NOT NULL) - * @mask: requested permissions mask - * - * Returns: %0 else error code if error or permission denied - */ -static inline int common_perm_path(const char *op, const struct path *path, - u32 mask) -{ - struct path_cond cond = { d_backing_inode(path->dentry)->i_uid, - d_backing_inode(path->dentry)->i_mode - }; - if (!path_mediated_fs(path->dentry)) - return 0; - - return common_perm(op, path, mask, &cond); -} - /** * common_perm_rm - common permission wrapper for operations doing rm * @op: operation being checked @@ -274,7 +274,7 @@ static int apparmor_path_mknod(const struct path *dir, struct dentry *dentry, static int apparmor_path_truncate(const struct path *path) { - return common_perm_path(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE); + return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE); } static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry, @@ -333,17 +333,17 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d static int apparmor_path_chmod(const struct path *path, umode_t mode) { - return common_perm_path(OP_CHMOD, path, AA_MAY_CHMOD); + return common_perm_cond(OP_CHMOD, path, AA_MAY_CHMOD); } static int apparmor_path_chown(const struct path *path, kuid_t uid, kgid_t gid) { - return common_perm_path(OP_CHOWN, path, AA_MAY_CHOWN); + return common_perm_cond(OP_CHOWN, path, AA_MAY_CHOWN); } static int apparmor_inode_getattr(const struct path *path) { - return common_perm_path(OP_GETATTR, path, AA_MAY_META_READ); + return common_perm_cond(OP_GETATTR, path, AA_MAY_META_READ); } static int apparmor_file_open(struct file *file, const struct cred *cred) diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 441efc965f2b..59c891ad1270 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -825,7 +825,8 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, if (error) goto fail_profile; - error = aa_calc_profile_hash(profile, e.version, start, + if (aa_g_hash_policy) + error = aa_calc_profile_hash(profile, e.version, start, e.pos - start); if (error) goto fail_profile; @@ -841,11 +842,13 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, list_add_tail(&ent->list, lh); } udata->abi = e.version & K_ABI_MASK; - udata->hash = aa_calc_hash(udata->data, udata->size); - if (IS_ERR(udata->hash)) { - error = PTR_ERR(udata->hash); - udata->hash = NULL; - goto fail; + if (aa_g_hash_policy) { + udata->hash = aa_calc_hash(udata->data, udata->size); + if (IS_ERR(udata->hash)) { + error = PTR_ERR(udata->hash); + udata->hash = NULL; + goto fail; + } } return 0; From 12eb87d50bfe234c3f964e9fb47bbd0135010c13 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:08 -0800 Subject: [PATCH 0426/1587] apparmor: update cap audit to check SECURITY_CAP_NOAUDIT apparmor should be checking the SECURITY_CAP_NOAUDIT constant. Also in complain mode make it so apparmor can elect to log a message, informing of the check. Signed-off-by: John Johansen --- security/apparmor/capability.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 1d2e2de5515f..ed0a3e6b8022 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "include/apparmor.h" #include "include/capability.h" @@ -55,6 +56,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) * audit_caps - audit a capability * @profile: profile being tested for confinement (NOT NULL) * @cap: capability tested + @audit: whether an audit record should be generated * @error: error code returned by test * * Do auditing of capability and handle, audit/complain/kill modes switching @@ -62,13 +64,16 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: 0 or sa->error on success, error code on failure */ -static int audit_caps(struct aa_profile *profile, int cap, int error) +static int audit_caps(struct aa_profile *profile, int cap, int audit, + int error) { struct audit_cache *ent; int type = AUDIT_APPARMOR_AUTO; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); sa.u.cap = cap; aad(&sa)->error = error; + if (audit == SECURITY_CAP_NOAUDIT) + aad(&sa)->info = "optional: no audit"; if (likely(!error)) { /* test if auditing is being forced */ @@ -129,11 +134,10 @@ int aa_capable(struct aa_profile *profile, int cap, int audit) { int error = profile_capable(profile, cap); - if (!audit) { - if (COMPLAIN_MODE(profile)) - return complain_error(error); - return error; + if (audit == SECURITY_CAP_NOAUDIT) { + if (!COMPLAIN_MODE(profile)) + return error; } - return audit_caps(profile, cap, error); + return audit_caps(profile, cap, audit, error); } From e025be0f26d5597b0a2bdfa65145a0171e77b614 Mon Sep 17 00:00:00 2001 From: William Hua Date: Sun, 15 Jan 2017 16:49:28 -0800 Subject: [PATCH 0427/1587] apparmor: support querying extended trusted helper extra data Allow a profile to carry extra data that can be queried via userspace. This provides a means to store extra data in a profile that a trusted helper can extract and use from live policy. Signed-off-by: William Hua Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 139 +++++++++++++++++++++++++++++ security/apparmor/include/policy.h | 16 ++++ security/apparmor/lsm.c | 1 + security/apparmor/policy.c | 23 +++++ security/apparmor/policy_unpack.c | 66 ++++++++++++++ 5 files changed, 245 insertions(+) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 7613a28f157e..6834000640d7 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -213,6 +213,144 @@ static const struct file_operations aa_fs_profile_remove = { .llseek = default_llseek, }; +/** + * query_data - queries a policy and writes its data to buf + * @buf: the resulting data is stored here (NOT NULL) + * @buf_len: size of buf + * @query: query string used to retrieve data + * @query_len: size of query including second NUL byte + * + * The buffers pointed to by buf and query may overlap. The query buffer is + * parsed before buf is written to. + * + * The query should look like "